home *** CD-ROM | disk | FTP | other *** search
- /* Display generation from window structure and buffer text.
- Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
- Copyright (C) 1995 Amdahl Corporation.
- Copyright (C) 1995 Ben Wing.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- /* This file has been Mule-ized. */
-
- /* Author: Chuck Thompson */
-
- /*****************************************************************************
- The Golden Rules of Redisplay
-
- First: It Is Better To Be Correct Than Fast
- Second: Though Shall Not Run Elisp From Within Redisplay
- Third: It Is Better To Be Fast Than Not To Be
- ****************************************************************************/
-
- #include <config.h>
- #include "lisp.h"
-
- #include "buffer.h"
- #include "commands.h"
- #include "debug.h"
- #include "device.h"
- #include "extents.h"
- #include "faces.h"
- #include "frame.h"
- #include "glyphs.h"
- #include "insdel.h"
- #include "process.h"
- #include "redisplay.h"
- #include "toolbar.h"
- #include "window.h"
-
- /* Return value to indicate a failure by an add_*_rune routine to add
- a rune, but no propagation information needs to be returned. */
- #define ADD_FAILED (prop_block_dynarr *) 1
-
- #define BEGIN_GLYPHS 0
- #define END_GLYPHS 1
- #define LEFT_GLYPHS 2
- #define RIGHT_GLYPHS 3
-
- /* Set the vertical clip to 0 if we are currently updating the line
- start cache. Otherwise for buffers of line height 1 it may fail to
- be able to work properly because regenerate_window will not layout
- a single line. */
- #define VERTICAL_CLIP(w, display) \
- (updating_line_start_cache \
- ? 0 \
- : ((WINDOW_IS_TTY (w) | (!display && scroll_on_clipped_lines)) \
- ? INT_MAX \
- : vertical_clip))
-
- /*
- * Prototypes for all functions defined in redisplay.c.
- */
- struct display_block *get_display_block_from_line (struct display_line *dl,
- enum display_type type);
- layout_bounds calculate_display_line_boundaries (struct window *w,
- int modeline);
- static Bufpos generate_display_line (struct window *w, struct display_line *dl,
- int bounds, Bufpos start_pos,
- int start_col, prop_block_dynarr **prop,
- int type);
- static void generate_modeline (struct window *w, struct display_line *dl,
- int type);
- static prop_block_dynarr *add_emchar_rune (pos_data *data);
- static prop_block_dynarr *add_string_of_bufbyte_runes (pos_data *data,
- Bufbyte *c_string,
- Bytecount c_length,
- int no_prop);
- static prop_block_dynarr *add_string_of_emchar_runes (pos_data *data,
- Emchar *e_string,
- Bytecount e_length);
- static prop_block_dynarr *add_blank_rune (pos_data *data, struct window *w,
- int char_tab_width);
- static prop_block_dynarr *add_octal_runes (pos_data *data);
- static prop_block_dynarr *add_control_char_runes (pos_data *data,
- struct buffer *b);
- static prop_block_dynarr *add_disp_table_entry_runes (pos_data *data,
- Lisp_Object entry);
- static prop_block_dynarr *add_propagation_runes (prop_block_dynarr **prop,
- pos_data *data);
- static prop_block_dynarr *add_glyph_rune (pos_data *data,
- struct glyph_block *gb,
- int pos_type, int allow_cursor,
- struct glyph_cache_element *inst);
- static prop_block_dynarr *add_glyph_runes (pos_data *data,
- int pos_type);
- static Bufpos create_text_block (struct window *w, struct display_line *dl,
- Bufpos start_pos, int start_col,
- prop_block_dynarr **prop, int type);
- static int create_overlay_glyph_block (struct window *w,
- struct display_line *dl);
- static void create_left_glyph_block (struct window *w,
- struct display_line *dl,
- int overlay_width);
- static void create_right_glyph_block (struct window *w,
- struct display_line *dl);
- static void regenerate_window (struct window *w, Bufpos start_pos,
- Bufpos point, int type);
- static void regenerate_window_point_center (struct window *w, Bufpos point,
- int type);
- int window_half_pixpos (struct window *w);
- int line_at_center (struct window *w, int type);
- Bufpos point_at_center (struct window *w, int type, int regen, Bufpos start,
- Bufpos point);
- static void redisplay_window (Lisp_Object window, int skip_selected);
- static void redisplay_windows (Lisp_Object window, int skip_selected);
- static int redisplay_frame (struct frame *f);
- void redisplay (void);
- static void decode_mode_spec (struct window *w, Emchar spec, int type);
- static void free_display_line (struct display_line *dl);
- void free_display_structs (struct window_mirror *mir);
- static int point_visible (struct window *w, Bufpos point, int type);
- static void update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
- Bufpos point, int no_regen);
- static Bufpos line_start_cache_start (struct window *w);
- static Bufpos line_start_cache_end (struct window *w);
-
- /* This used to be 10 but 30 seems to give much better performance. */
- #define INIT_MAX_PREEMPTS 30
- static int max_preempts;
-
- #define REDISPLAY_PREEMPTION_CHECK \
- do { \
- preempted = 0; \
- if (!disable_preemption && \
- ((preemption_count < max_preempts) || !NILP (Vexecuting_macro))) \
- if (!INTERACTIVE || detect_input_pending ()) { \
- preempted = 1; \
- } \
- } while (0)
-
- /*
- * Redisplay global variables.
- */
-
- /* #### probably temporary */
- int cache_adjustment;
-
- emchar_dynarr *mode_string_buffer;
- bufbyte_dynarr *mode_spec;
-
- int in_display; /* 1 if in redisplay. */
-
- int disable_preemption; /* Used for debugging redisplay and for
- force-redisplay. */
-
- /* We only allow max_preempts preemptions before we force a redisplay. */
- static int preemption_count;
-
- /* Minimum pixel height of clipped bottom display line. */
- int vertical_clip;
-
- /* Minimum visible pixel width of clipped glyphs at right margin. */
- int horizontal_clip;
-
- /* Set if currently inside update_line_start_cache. */
- int updating_line_start_cache;
-
- /* Nonzero means reading single-character input with prompt
- so put cursor on minibuffer after the prompt. */
- int cursor_in_echo_area;
- Lisp_Object Qcursor_in_echo_area;
-
- /* Nonzero means truncate lines in all windows less wide than the frame */
- int truncate_partial_width_windows;
-
- /* non-nil if a buffer has changed since the last time redisplay completed */
- int buffers_changed;
- int buffers_changed_set;
-
- /* non-nil if hscroll has changed somewhere or a buffer has been
- narrowed or widened */
- int clip_changed;
- int clip_changed_set;
-
- /* non-nil if any extent has changed since the last time redisplay completed */
- int extents_changed;
- int extents_changed_set;
-
- /* non-nil if any face has changed since the last time redisplay completed */
- int faces_changed;
-
- /* Nonzero means some frames have been marked as garbaged */
- int frame_changed;
-
- /* This variable is 1 if the menubar widget has to be updated.
- It is set to 1 by set-menubar-dirty-flag and cleared when the widget
- has been indapted. */
- /* indapted???? */
- int menubar_changed;
- int menubar_changed_set;
-
- /* true iff we should redraw the modelines on the next redisplay */
- int modeline_changed;
- int modeline_changed_set;
-
- /* non-nil if point has changed in some buffer since the last time
- redisplay completed */
- int point_changed;
- int point_changed_set;
-
- /* non-nil if some frame has changed its size */
- int size_changed;
-
- /* non-nil if some device has signaled that it wants to change size */
- int asynch_device_change_pending;
-
- /* non-nil if any toolbar has changed */
- int toolbar_changed;
- int toolbar_changed_set;
-
- /* non-nil if any window has changed since the last time redisplay completed */
- int windows_changed;
-
- /* non-nil if any frame's window struture has changed since the last
- time redisplay completed */
- int windows_structure_changed;
-
- /* If non-nil, use vertical bar cursor. */
- Lisp_Object Vbar_cursor;
-
- /* #### All of the following crap is on probation. */
-
-
- int visible_bell; /* If true and the terminal will support it
- then the frame will flash instead of
- beeping when an error occurs */
-
- /* Nonzero means no need to redraw the entire frame on resuming
- a suspended Emacs. This is useful on terminals with multiple pages,
- where one page is used for Emacs and another for all else. */
- int no_redraw_on_reenter;
-
- Lisp_Object Vwindow_system; /* nil or a symbol naming the window system
- under which emacs is running
- ('x is the only current possibility) */
- Lisp_Object Vinitial_window_system;
-
- /* Version number of X windows: 10, 11 or nil. */
- Lisp_Object Vwindow_system_version;
-
- Lisp_Object Vglobal_mode_string;
- /* The number of lines to try scrolling a
- window by when point leaves the window; if
- it is <=0 then point is centered in the window */
- int scroll_step;
- /* Whether to display line numbers in the modeline. */
- int line_number_mode;
- /* Marker for where to display an arrow on top of the buffer text. */
- Lisp_Object Voverlay_arrow_position;
- /* String to display for the arrow. */
- Lisp_Object Voverlay_arrow_string;
-
- /* #### END OF PROBATION */
-
- #if 0
- /* #### Chuck says: I think this needs more thought.
- Think about this for 19.14. */
- Lisp_Object Vpre_redisplay_hook, Vpost_redisplay_hook;
- Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook;
- #endif
-
- int last_display_warning_tick, display_warning_tick;
- Lisp_Object Qdisplay_warning_buffer;
- int inhibit_warning_display;
-
- Lisp_Object Vleft_margin_width, Vright_margin_width;
- Lisp_Object Vminimum_line_ascent, Vminimum_line_descent;
- Lisp_Object Vuse_left_overflow, Vuse_right_overflow;
-
-
- /*****************************************************************************
- get_display_block_from_line
-
- Return the display block from DL of the given TYPE. A display line can have
- only one display block of each possible type. If DL does not have a block
- of type TYPE, one will be created and added to DL.
- ****************************************************************************/
- struct display_block *
- get_display_block_from_line (struct display_line *dl, enum display_type type)
- {
- int elt;
- struct display_block db;
-
- /* Check if this display line already has a block of the desired type and
- if so, return it. */
- if (dl->display_blocks)
- {
- for (elt = 0; elt < Dynarr_length (dl->display_blocks); elt++)
- {
- if (Dynarr_at (dl->display_blocks, elt).type == type)
- return (Dynarr_atp (dl->display_blocks, elt));
- }
-
- /* There isn't an active block of the desired type, but there
- might still be allocated blocks we need to reuse. */
- if (elt < Dynarr_largest (dl->display_blocks))
- {
- struct display_block *dbp = Dynarr_atp (dl->display_blocks, elt);
-
- /* 'add' the block to the list */
- Dynarr_increment (dl->display_blocks);
-
- /* initialize and return */
- dbp->type = type;
- return dbp;
- }
- }
- else
- {
- /* This line doesn't have any display blocks, so initialize the display
- bock array. */
- dl->display_blocks = Dynarr_new (struct display_block);
- }
-
- /* The line doesn't have a block of the desired type so go ahead and create
- one and add it to the line. */
- memset (&db, 0, sizeof (struct display_block));
- db.type = type;
- db.runes = Dynarr_new (struct rune);
- Dynarr_add (dl->display_blocks, db);
-
- /* Return the newly added display block. */
- elt = Dynarr_length (dl->display_blocks) - 1;
-
- return Dynarr_atp (dl->display_blocks, elt);
- }
-
- static int
- tab_char_width (struct window *w)
- {
- struct buffer *b = XBUFFER (w->buffer);
- int char_tab_width = XINT (b->tab_width);
-
- if (char_tab_width <= 0 || char_tab_width > 1000) char_tab_width = 8;
-
- return char_tab_width;
- }
-
- static int
- space_width (struct window *w)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- struct font_metric_info fm;
-
- /* While tabs are traditional composed of spaces, for variable-width
- fonts the space character tends to give too narrow a value. So
- we use 'n' instead. Except that we don't. We use the default
- character width for the default face. If this is actually
- defined by the font then it is probably the best thing to
- actually use. If it isn't, we have assumed it is 'n' and have
- already calculated its width. Thus we can avoid a call to
- XTextWidth on X frames by just querying the default width. */
- DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX),
- &fm));
- return fm.width;
- }
-
- static int
- tab_pix_width (struct window *w)
- {
- return (space_width (w) * tab_char_width (w));
- }
-
- /*****************************************************************************
- next_tab_position
-
- Given a pixel position in a window, return the pixel location of the next
- tabstop. Tabs are calculated from the left window edge in terms of spaces
- displayed in the default face. Formerly the space width was determined
- using the currently active face. That method leads to tabstops which do not
- line up.
- ****************************************************************************/
- static int
- next_tab_position (struct window *w, int start_pixpos, int left_pixpos)
- {
- int n_pos = left_pixpos;
- int pix_tab_width = tab_pix_width (w);
-
- /* Adjust n_pos for any hscrolling which has happened. */
- if (w->hscroll > 1)
- n_pos -= space_width (w) * (w->hscroll - 1);
-
- while (n_pos <= start_pixpos)
- n_pos += pix_tab_width;
-
- return n_pos;
- }
-
- /*****************************************************************************
- calculate_display_line_boundaries
-
- For the given window, calculate the outside and margin boundaries for a
- display line. The whitespace boundaries must be calculated by the text
- layout routines.
- ****************************************************************************/
- layout_bounds
- calculate_display_line_boundaries (struct window *w, int modeline)
- {
- layout_bounds bounds;
-
- /* Set the outermost boundaries which are the boundaries of the
- window itself minus the gutters (and minus the scrollbars if this
- is for the modeline). */
- if (!modeline)
- {
- bounds.left_out = WINDOW_TEXT_LEFT (w);
- bounds.right_out = WINDOW_TEXT_RIGHT (w);
- }
- else
- {
- bounds.left_out = WINDOW_MODELINE_LEFT (w);
- bounds.right_out = WINDOW_MODELINE_RIGHT (w);
- }
-
- /* The inner boundaries mark where the glyph margins are located. */
- bounds.left_in = bounds.left_out + window_left_margin_width (w);
- bounds.right_in = bounds.right_out - window_right_margin_width (w);
-
- /* We cannot fully calculate the whitespace boundaries as they
- depend on the contents of the line being displayed. */
- bounds.left_white = bounds.left_in;
- bounds.right_white = bounds.right_in;
-
- return bounds;
- }
-
- /*****************************************************************************
- generate_display_line
-
- Given a display line and a starting position, ensure that the contents of
- the display line accurately represent the visual representation of the
- buffer contents starting from the given position when displayed in the given
- window. The display line ends when the contents of the line reach the right
- boundary of the given window.
- ****************************************************************************/
- static Bufpos
- generate_display_line (struct window *w, struct display_line *dl, int bounds,
- Bufpos start_pos, int start_col,
- prop_block_dynarr **prop, int type)
- {
- Bufpos ret_bufpos;
- int overlay_width;
-
- /* If our caller hasn't already set the boundaries, then do so now. */
- if (!bounds)
- dl->bounds = calculate_display_line_boundaries (w, 0);
-
- /* Reset what this line is using. */
- if (dl->display_blocks)
- Dynarr_reset (dl->display_blocks);
- if (dl->left_glyphs)
- {
- Dynarr_free (dl->left_glyphs);
- dl->left_glyphs = 0;
- }
- if (dl->right_glyphs)
- {
- Dynarr_free (dl->right_glyphs);
- dl->right_glyphs = 0;
- }
-
- /* We aren't generating a modeline at the moment. */
- dl->modeline = 0;
-
- /* Create a display block for the text region of the line. */
- ret_bufpos = create_text_block (w, dl, start_pos, start_col, prop, type);
- dl->bufpos = start_pos;
- if (dl->end_bufpos < dl->bufpos)
- dl->end_bufpos = dl->bufpos;
-
- if (MARKERP (Voverlay_arrow_position)
- && EQ (w->buffer, Fmarker_buffer (Voverlay_arrow_position))
- && start_pos == marker_position (Voverlay_arrow_position)
- && (STRINGP (Voverlay_arrow_string)
- || GLYPHP (Voverlay_arrow_string)))
- {
- overlay_width = create_overlay_glyph_block (w, dl);
- }
- else
- overlay_width = 0;
-
- /* If there are left glyphs associated with any character in the
- text block, then create a display block to handle them. */
- if (dl->left_glyphs != NULL && Dynarr_length (dl->left_glyphs))
- create_left_glyph_block (w, dl, overlay_width);
-
- /* If there are right glyphs associated with any character in the
- text block, then create a display block to handle them. */
- if (dl->right_glyphs != NULL && Dynarr_length (dl->right_glyphs))
- create_right_glyph_block (w, dl);
-
- /* In the future additional types of display blocks may be generated
- here. */
-
- return ret_bufpos;
- }
-
- /*****************************************************************************
- generate_modeline
-
- Ensure that the given display line DL accurately represents the modeline for
- the given window.
- ****************************************************************************/
- static void
- generate_modeline (struct window *w, struct display_line *dl, int type)
- {
- struct buffer *b = XBUFFER (w->buffer);
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- /* Unlike display line and rune pointers, this one can't change underneath
- our feet. */
- struct display_block *db = get_display_block_from_line (dl, TEXT);
- struct font_metric_info fm;
- int c_pixpos, max_pixpos, min_pixpos;
-
- /* This will actually determine incorrect inside boundaries for the
- modeline since it ignores the margins. However being aware of this fact
- we never use those values anywhere so it doesn't matter. */
- dl->bounds = calculate_display_line_boundaries (w, 1);
-
- /* We are generating a modeline. */
- dl->modeline = 1;
- dl->cursor_elt = -1;
-
- /* Reset the runes on the modeline. */
- Dynarr_reset (db->runes);
-
- if (!WINDOW_HAS_MODELINE_P (w))
- {
- struct rune rb;
-
- /* If there is a horizontal scrollbar, don't add anything. */
- if (window_scrollbar_height (w))
- return;
-
- dl->ascent = DEVMETH (d, divider_height, ());
- dl->descent = 0;
- /* The modeline is at the bottom of the gutters. */
- dl->ypos = WINDOW_BOTTOM (w);
-
- rb.findex = MODELINE_INDEX;
- rb.extent = Qnil;
- rb.xpos = dl->bounds.left_out;
- rb.width = dl->bounds.right_out - dl->bounds.left_out;
- rb.bufpos = 0;
- rb.endpos = 0;
- rb.type = HLINE;
- rb.object.hline.thickness = 1;
- rb.object.hline.yoffset = 0;
- rb.cursor_type = NO_CURSOR;
-
- if (!EQ (Qzero, w->modeline_shadow_thickness)
- && FRAME_IS_WIN (f))
- {
- int shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
-
- dl->ypos -= shadow_thickness;
- rb.xpos += shadow_thickness;
- rb.width -= 2 * shadow_thickness;
- }
-
- Dynarr_add (db->runes, rb);
- return;
- }
-
- DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, MODELINE_INDEX),
- &fm));
-
- dl->ascent = fm.ascent;
- dl->descent = fm.descent;
- /* The modeline is at the bottom of the gutters. */
- dl->ypos = WINDOW_BOTTOM (w) - dl->descent;
-
- c_pixpos = dl->bounds.left_out;
- min_pixpos = dl->bounds.left_out;
- max_pixpos = dl->bounds.right_out;
-
- if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_IS_WIN (f))
- {
- int shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
-
- dl->ypos -= shadow_thickness;
- c_pixpos += shadow_thickness;
- min_pixpos += shadow_thickness;
- max_pixpos -= shadow_thickness;
- }
-
- /* This recursively builds up the modeline. */
- Dynarr_reset (mode_string_buffer);
- generate_modeline_string (w, 0, 0, -1, b->modeline_format, 0,
- max_pixpos - min_pixpos, MODELINE_INDEX, type);
-
- if (Dynarr_length (mode_string_buffer))
- {
- pos_data data;
-
- memset (&data, 0, sizeof (pos_data));
- data.d = d;
- data.db = db;
- data.dl = dl;
- data.findex = MODELINE_INDEX;
- data.pixpos = min_pixpos;
- data.max_pixpos = max_pixpos;
- data.bufpos = 0;
- data.endpos = 0;
- data.width = 0;
- data.cursor_type = NO_CURSOR;
- data.start_col = data.start_col_enabled = 0;
- XSETWINDOW (data.window, w);
-
- add_string_of_emchar_runes (&data, Dynarr_atp (mode_string_buffer, 0),
- Dynarr_length (mode_string_buffer));
-
- if (Dynarr_length (db->runes))
- {
- struct rune *rb =
- Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
- c_pixpos = rb->xpos + rb->width;
- }
- else
- c_pixpos = min_pixpos;
-
- /* If we don't reach the right side of the window, add a blank
- rune to make up the difference. This usually only occurs if
- the modeline face is using a proportional width font or a
- fixed width font of a different size from the default face
- font. */
-
- if (c_pixpos < max_pixpos)
- {
- data.pixpos = c_pixpos;
- data.width = max_pixpos - data.pixpos;
-
- add_blank_rune (&data, NULL, 0);
- }
- }
- }
-
- static int
- add_string_to_mode_string_buffer (Bufbyte *str, int pos, int min, int max)
- {
- int end;
- Bufbyte *cur_pos = str;
- Emchar space = ' ';
-
- while (Dynarr_length (mode_string_buffer) < pos)
- Dynarr_add (mode_string_buffer, ' ');
-
- end = Dynarr_length (mode_string_buffer) + strlen ((char *) str);
- if (max != -1)
- end = min (max, end);
-
- while (pos < end && *cur_pos)
- {
- Emchar ch = charptr_to_emchar (cur_pos);
- Dynarr_add (mode_string_buffer, ch);
- INC_CHARPTR (cur_pos);
- pos++;
- }
-
- while (Dynarr_length (mode_string_buffer) < min)
- Dynarr_add (mode_string_buffer, space);
-
- return Dynarr_length (mode_string_buffer);
- }
-
- /* If max_pos is == -1, it is considered to be infinite. The same is
- true of max_pixsize. */
-
- #define SET_CURRENT_MODE_STRING_PIXSIZE \
- cur_pixsize = DEVMETH (d, text_width, \
- (w, FACE_CACHE_ELEMENT_FONT (w, findex), \
- Dynarr_atp (mode_string_buffer, 0), \
- Dynarr_length (mode_string_buffer)))
-
- int
- generate_modeline_string (struct window *w, int pos, int min_pos, int max_pos,
- Lisp_Object elt, int depth, int max_pixsize,
- face_index findex, int type)
- {
- struct device *d = XDEVICE (XFRAME (w->frame)->device);
-
- /* #### Having to set the current buffer sucks. Do it for now, but
- later extend the necessary internal routines of stuff such as
- Fsymbol_value to take a buffer argument. */
- struct buffer *old_buffer = current_buffer;
- current_buffer = XBUFFER (w->buffer);
-
- tail_recurse:
- if (depth > 10)
- goto invalid;
-
- depth++;
-
- if (STRINGP (elt))
- {
- /* A string. Add to the display line and check for %-constructs
- within it. */
-
- Bufbyte *this = string_data (XSTRING (elt));
-
- while ((pos < max_pos || max_pos == -1) && *this)
- {
- Bufbyte *last = this;
-
- while (*this && *this != '%')
- this++;
-
- if (this != last)
- {
- /* The string is just a string. */
- int size = this - last + pos;
- int tmp_max = (max_pos == -1 ? size : min (size, max_pos));
-
- pos = add_string_to_mode_string_buffer (last, pos, pos, tmp_max);
- }
- else /* *this == '%' */
- {
- int spec_width = 0;
-
- this++; /* skip over '%' */
-
- /* We can't allow -ve args due to the "%-" construct.
- * Argument specifies minwidth but not maxwidth
- * (maxwidth can be specified by
- * (<negative-number> . <stuff>) modeline elements)
- */
- while (isdigit (*this))
- {
- spec_width = spec_width * 10 + (*this - '0');
- this++;
- }
- spec_width += pos;
-
- if (*this == 'M')
- {
- pos = generate_modeline_string (w, pos, spec_width, max_pos,
- Vglobal_mode_string, depth,
- max_pixsize, findex, type);
- }
- else if (*this == '-')
- {
- int num_to_add;
-
- if (max_pixsize < 0)
- num_to_add = 0;
- else if (max_pos != -1)
- num_to_add = max_pos - pos;
- else
- {
- int cur_pixsize;
- int dash_pixsize;
- Emchar ch = '-';
- SET_CURRENT_MODE_STRING_PIXSIZE;
-
- dash_pixsize =
- DEVMETH (d, text_width,
- (w, FACE_CACHE_ELEMENT_FONT (w, findex), &ch,
- 1));
-
- num_to_add = (max_pixsize - cur_pixsize) / dash_pixsize;
- num_to_add++;
- }
-
- while (num_to_add--)
- pos = add_string_to_mode_string_buffer ((Bufbyte *) "-",
- pos, pos, max_pos);
- }
- else if (*this != 0)
- {
- Bufbyte *str;
- Emchar ch = charptr_to_emchar (this);
- decode_mode_spec (w, ch, type);
-
- str = Dynarr_atp (mode_spec, 0);
- pos = add_string_to_mode_string_buffer (str, pos, pos,
- max_pos);
- }
-
- /* NOT this++. There could be any sort of character at
- the current position. */
- INC_CHARPTR (this);
- }
-
- if (max_pixsize > 0)
- {
- int cur_pixsize;
- SET_CURRENT_MODE_STRING_PIXSIZE;
-
- if (cur_pixsize >= max_pixsize)
- break;
- }
- }
- }
- else if (SYMBOLP (elt))
- {
- /* A symbol: process the value of the symbol recursively
- as if it appeared here directly. Avoid error if symbol void.
- Special case: if value of symbol is a string, output the string
- literally. */
- Lisp_Object tem = Fboundp (elt);
-
- if (!NILP (tem))
- {
- tem = Fsymbol_value (elt);
-
- /* If value is a string, output that string literally:
- don't check for % within it. */
- if (STRINGP (tem))
- {
- pos =
- add_string_to_mode_string_buffer (string_data (XSTRING (tem)),
- pos, min_pos, max_pos);
- }
- /* Give up right away for nil or t. */
- else if (!EQ (tem, elt))
- {
- elt = tem;
- goto tail_recurse;
- }
- }
- }
- else if (CONSP (elt))
- {
- /* A cons cell: three distinct cases.
- * If first element is a string or a cons, process all the elements
- * and effectively concatenate them.
- * If first element is a negative number, truncate displaying cdr to
- * at most that many characters. If positive, pad (with spaces)
- * to at least that many characters.
- * If first element is a symbol, process the cadr or caddr recursively
- * according to whether the symbol's value is non-nil or nil.
- */
- Lisp_Object car, tem;
-
- car = XCAR (elt);
- if (SYMBOLP (car))
- {
- tem = Fboundp (car);
- elt = XCDR (elt);
- if (!CONSP (elt))
- goto invalid;
- /* elt is now the cdr, and we know it is a cons cell.
- Use its car if CAR has a non-nil value. */
- if (!NILP (tem))
- {
- tem = Fsymbol_value (car);
- if (!NILP (tem))
- {
- elt = XCAR (elt);
- goto tail_recurse;
- }
- }
- /* Symbol's value is nil (or symbol is unbound)
- * Get the cddr of the original list
- * and if possible find the caddr and use that.
- */
- elt = XCDR (elt);
- if (NILP (elt))
- ;
- else if (!CONSP (elt))
- goto invalid;
- else
- {
- elt = XCAR (elt);
- goto tail_recurse;
- }
- }
- else if (INTP (car))
- {
- int lim = XINT (car);
-
- elt = XCDR (elt);
-
- if (lim < 0)
- {
- /* Negative int means reduce maximum width.
- * DO NOT change MIN_PIXPOS here!
- * (20 -10 . foo) should truncate foo to 10 col
- * and then pad to 20.
- */
- if (max_pos == -1)
- max_pos = pos - lim;
- else
- max_pos = min (max_pos, pos - lim);
- }
- else if (lim > 0)
- {
- /* Padding specified. Don't let it be more than
- * current maximum.
- */
- lim += pos;
- if (max_pos != -1 && lim > max_pos)
- lim = max_pos;
- /* If that's more padding than already wanted, queue it.
- * But don't reduce padding already specified even if
- * that is beyond the current truncation point.
- */
- if (lim > min_pos)
- min_pos = lim;
- }
- goto tail_recurse;
- }
- else if (STRINGP (car) || CONSP (car))
- {
- int limit = 50;
- /* LIMIT is to protect against circular lists. */
- while (CONSP (elt) && --limit > 0
- && (pos < max_pos || max_pos == -1))
- {
- pos = generate_modeline_string (w, pos, pos, max_pos, XCAR (elt),
- depth, max_pixsize, findex,
- type);
- elt = XCDR (elt);
- }
- }
- }
- else
- {
- invalid:
- pos =
- add_string_to_mode_string_buffer ((Bufbyte *) GETTEXT ("*invalid*"),
- pos, min_pos, max_pos);
- }
-
- if (min_pos > pos)
- {
- add_string_to_mode_string_buffer ((Bufbyte *) "", pos, min_pos, -1);
- }
-
- current_buffer = old_buffer;
- return pos;
- }
-
- /*****************************************************************************
- add_hscroll_rune
-
- Adds an hscroll glyph to a display block. If this is called, then the
- block had better be empty.
-
- Yes, there are multiple places where this function is called but that
- is the way it has to be. Each calling function has to deal with
- start_col_enabled a little differently depending on the object being
- worked with.
- ****************************************************************************/
- static prop_block_dynarr *
- add_hscroll_rune (pos_data *data)
- {
- struct glyph_block gb;
- prop_block_dynarr *retval;
- Bufpos old_cursor_bufpos = data->cursor_bufpos;
- enum cursor_type old_cursor_type = data->cursor_type;
- Bufpos old_bufpos = data->bufpos;
-
- if (data->cursor_type == CURSOR_ON
- && data->cursor_bufpos >= data->start_col_enabled
- && data->cursor_bufpos <= data->bufpos)
- {
- data->cursor_bufpos = data->start_col_enabled;
- }
- else
- {
- data->cursor_type = NO_CURSOR;
- }
-
- data->endpos = data->bufpos;
- data->bufpos = data->start_col_enabled;
-
- gb.extent = Qnil;
- gb.glyph = Vhscroll_glyph;
- retval = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
- GLYPH_CACHE_ELEMENT (XWINDOW (data->window),
- HSCROLL_GLYPH_INDEX));
-
- data->endpos = 0;
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- data->bufpos = old_bufpos;
-
- data->start_col_enabled = 0;
- return retval;
- }
-
- /*****************************************************************************
- add_emchar_rune
-
- Adds a character rune to a display block. If there is not enough room to
- fit the rune on the display block (as determined by the MAX_PIXPOS) then
- it adds nothing and returns ADD_FAILED.
- ****************************************************************************/
- static prop_block_dynarr *
- add_emchar_rune (pos_data *data)
- {
- struct rune rb, *crb;
- int width, local;
-
- if (data->start_col)
- {
- data->start_col--;
-
- if (data->start_col)
- return NULL;
- }
-
- if (data->start_col_enabled)
- {
- return add_hscroll_rune (data);
- }
-
- if (data->width)
- width = data->width;
- else
- {
- struct window *w = XWINDOW (data->window);
- width =
- DEVMETH (data->d, text_width, (w,
- FACE_CACHE_ELEMENT_FONT (w, data->findex),
- &data->ch, 1));
- }
-
- if (data->pixpos + width > data->max_pixpos)
- {
- return ADD_FAILED;
- }
-
- if (Dynarr_length (data->db->runes) < Dynarr_largest (data->db->runes))
- {
- crb = Dynarr_atp (data->db->runes, Dynarr_length (data->db->runes));
- local = 0;
- }
- else
- {
- crb = &rb;
- local = 1;
- }
-
- crb->findex = data->findex;
- crb->extent = Qnil; /* only care about extent with glyphs */
- crb->xpos = data->pixpos;
- crb->width = width;
- crb->bufpos = data->bufpos;
- crb->type = CHAR;
- crb->object.ch = data->ch;
- crb->endpos = 0;
-
- if (data->cursor_type == CURSOR_ON)
- {
- if (data->bufpos == data->cursor_bufpos)
- {
- crb->cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- }
- else
- crb->cursor_type = CURSOR_OFF;
- }
- else if (data->cursor_type == NEXT_CURSOR)
- {
- crb->cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- data->cursor_type = NO_CURSOR;
- }
- else if (data->cursor_type == IGNORE_CURSOR)
- crb->cursor_type = IGNORE_CURSOR;
- else
- crb->cursor_type = CURSOR_OFF;
-
- if (local)
- Dynarr_add (data->db->runes, *crb);
- else
- Dynarr_increment (data->db->runes);
-
- data->pixpos += width;
-
- return NULL;
- }
-
- /*****************************************************************************
- add_string_of_bufbyte_runes
-
- Given a string C_STRING of length C_LENGTH, call add_emchar_rune for
- each character in the string. Propagate any left-over data unless
- NO_PROP is non-zero.
- ****************************************************************************/
- static prop_block_dynarr *
- add_string_of_bufbyte_runes (pos_data *data, Bufbyte *c_string,
- Bytecount c_length, int no_prop)
- {
- Bufbyte *pos, *end = c_string + c_length;
- prop_block_dynarr *prop;
-
- /* #### This function is too simplistic. It needs to do the same
- sort of character interpretation (display-table lookup,
- ctl-arrow checking), etc. that create_text_block() does.
- The functionality to do this in that routine needs to be
- modularized. */
-
- for (pos = c_string; pos < end;)
- {
- data->ch = charptr_to_emchar (pos);
-
- prop = add_emchar_rune (data);
-
- if (prop)
- {
- if (no_prop)
- return ADD_FAILED;
- else
- {
- struct prop_block pb;
- Bytecount len = end - pos;
- prop = Dynarr_new (struct prop_block);
-
- pb.type = PROP_STRING;
- pb.data.p_string.str =
- (Bufbyte *) xmalloc (sizeof (Bufbyte) * len);
- strncpy ((char *) pb.data.p_string.str, (char *) pos, len);
- pb.data.p_string.len = len;
-
- Dynarr_add (prop, pb);
- return prop;
- }
- }
- INC_CHARPTR (pos);
- assert (pos <= end);
- }
-
- return NULL;
- }
-
- /*****************************************************************************
- add_string_of_emchar_runes
-
- Given a string E_STRING of length E_LENGTH, call add_emchar_rune for
- each character in the string. Doesn't propogate any data. This is
- currently only used by generate_modeline_string.
- ****************************************************************************/
- static prop_block_dynarr *
- add_string_of_emchar_runes (pos_data *data, Emchar *e_string,
- Bytecount e_length)
- {
- Emchar *pos, *end = e_string + e_length;
- prop_block_dynarr *prop;
-
- for (pos = e_string; pos < end;)
- {
- data->ch = *pos;
- prop = add_emchar_rune (data);
-
- if (prop)
- return ADD_FAILED;
-
- INC_CHARPTR (pos);
- assert (pos <= end);
- }
-
- return NULL;
- }
-
- /*****************************************************************************
- add_blank_rune
-
- Add a single rune of the specified width. The area covered by this
- rune will be displayed in the foreground color of the associated
- face.
- ****************************************************************************/
- static prop_block_dynarr *
- add_blank_rune (pos_data *data, struct window *w, int char_tab_width)
- {
- struct rune rb;
-
- /* If data->start_col is not 0 then this call to add_blank_rune must have
- be to add it as a tab. */
- if (data->start_col)
- {
- /* assert (w != NULL) */
- prop_block_dynarr *retval;
-
- /* If we have still not fully scrolled horizontally, subtract
- the width of this tab and return. */
- if (char_tab_width < data->start_col)
- {
- data->start_col -= char_tab_width;
- return NULL;
- }
- else if (char_tab_width == data->start_col)
- data->width = 0;
- else
- {
- int spcwid = space_width (w);
-
- if (spcwid >= data->width)
- data->width = 0;
- else
- data->width -= spcwid;
- }
-
- data->start_col = 0;
- retval = add_hscroll_rune (data);
-
- /* Could be caused by the handling of the hscroll rune. */
- if (retval != NULL || !data->width)
- return retval;
- }
-
- /* Blank runes are always calculated to fit. */
- assert (data->pixpos + data->width <= data->max_pixpos);
-
- rb.findex = data->findex;
- rb.extent = Qnil; /* only care about extent with glyphs */
- rb.xpos = data->pixpos;
- rb.width = data->width;
- rb.bufpos = data->bufpos;
- rb.endpos = 0;
- rb.type = BLANK;
-
- if (data->cursor_type == CURSOR_ON)
- {
- if (data->bufpos == data->cursor_bufpos)
- {
- rb.cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- }
- else
- rb.cursor_type = CURSOR_OFF;
- }
- else if (data->cursor_type == NEXT_CURSOR)
- {
- rb.cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- data->cursor_type = NO_CURSOR;
- }
- else
- rb.cursor_type = CURSOR_OFF;
-
- Dynarr_add (data->db->runes, rb);
- data->pixpos += data->width;
-
- return NULL;
- }
-
- /*****************************************************************************
- add_octal_runes
-
- Add runes representing a character in octal.
- ****************************************************************************/
-
- #define ADD_NEXT_OCTAL_RUNE_CHAR do \
- { \
- if (add_failed || (add_failed = add_emchar_rune (data))) \
- { \
- struct prop_block pb; \
- if (!prop) \
- prop = Dynarr_new (struct prop_block); \
- \
- pb.type = PROP_CHAR; \
- pb.data.p_char.ch = data->ch; \
- pb.data.p_char.cursor_type = data->cursor_type; \
- Dynarr_add (prop, pb); \
- } \
- } while (0)
-
- static prop_block_dynarr *
- add_octal_runes (pos_data *data)
- {
- prop_block_dynarr *prop, *add_failed;
- Emchar orig_char = data->ch;
- enum cursor_type orig_cursor_type = data->cursor_type;
-
- /* Initialize */
- prop = NULL;
- add_failed = NULL;
-
- if (data->start_col)
- data->start_col--;
-
- if (!data->start_col)
- {
- if (data->start_col_enabled)
- {
- add_failed = add_hscroll_rune (data);
- }
- else
- {
- struct glyph_block gb;
- struct window *w = XWINDOW (data->window);
-
- gb.extent = Qnil;
- gb.glyph = Voctal_escape_glyph;
- add_failed =
- add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
- GLYPH_CACHE_ELEMENT (w, OCT_ESC_GLYPH_INDEX));
- }
- }
-
- /* We only propagate information if the glyph was partially
- added. */
- if (add_failed)
- return add_failed;
-
- data->cursor_type = IGNORE_CURSOR;
-
- if (data->ch >= 0x100)
- {
- /* If the character is an extended Mule character, it could have
- up to 19 bits. For the moment, we treat it as a seven-digit
- octal number. This is not that pretty, but whatever. */
- data->ch = (7 & (orig_char >> 18)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->ch = (7 & (orig_char >> 15)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->ch = (7 & (orig_char >> 12)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->ch = (7 & (orig_char >> 9)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
- }
-
- data->ch = (7 & (orig_char >> 6)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->ch = (7 & (orig_char >> 3)) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->ch = (7 & orig_char) + '0';
- ADD_NEXT_OCTAL_RUNE_CHAR;
-
- data->cursor_type = orig_cursor_type;
- return prop;
- }
-
- #undef ADD_NEXT_OCTAL_RUNE_CHAR
-
- /*****************************************************************************
- add_control_char_runes
-
- Add runes representing a control character to a display block.
- ****************************************************************************/
- static prop_block_dynarr *
- add_control_char_runes (pos_data *data, struct buffer *b)
- {
- if (!NILP (b->ctl_arrow))
- {
- prop_block_dynarr *prop;
- Emchar orig_char = data->ch;
- enum cursor_type old_cursor_type = data->cursor_type;
-
- /* Initialize */
- prop = NULL;
-
- if (data->start_col)
- data->start_col--;
-
- if (!data->start_col)
- {
- if (data->start_col_enabled)
- {
- prop_block_dynarr *retval;
-
- retval = add_hscroll_rune (data);
- if (retval)
- return retval;
- }
- else
- {
- struct glyph_block gb;
- struct window *w = XWINDOW (data->window);
-
- gb.extent = Qnil;
- gb.glyph = Vcontrol_arrow_glyph;
-
- /* We only propagate information if the glyph was partially
- added. */
- if (add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
- GLYPH_CACHE_ELEMENT (w, CONTROL_GLYPH_INDEX)))
- return ADD_FAILED;
- }
- }
-
- if (orig_char == 0177)
- data->ch = '?';
- else
- data->ch = orig_char ^ 0100;
- data->cursor_type = IGNORE_CURSOR;
-
- if (add_emchar_rune (data))
- {
- struct prop_block pb;
- if (!prop)
- prop = Dynarr_new (struct prop_block);
-
- pb.type = PROP_CHAR;
- pb.data.p_char.ch = data->ch;
- pb.data.p_char.cursor_type = data->cursor_type;
- Dynarr_add (prop, pb);
- }
-
- data->cursor_type = old_cursor_type;
- return prop;
- }
- else
- {
- return add_octal_runes (data);
- }
- }
-
- /*****************************************************************************
- add_disp_table_entry_runes
-
- Given a display table entry, call the appropriate functions to
- display each element of the entry.
- ****************************************************************************/
- static prop_block_dynarr *
- add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
- {
- prop_block_dynarr *prop = NULL;
-
- if (VECTORP (entry))
- {
- struct Lisp_Vector *de = XVECTOR (entry);
- long len = vector_length (de);
- int elt;
-
- for (elt = 0; elt < len; elt++)
- {
- if (NILP (de->contents[elt]))
- continue;
- else if (STRINGP (de->contents[elt]))
- {
- prop =
- add_string_of_bufbyte_runes
- (data,
- string_data (XSTRING (de->contents[elt])),
- string_length (XSTRING (de->contents[elt])),
- 0);
- }
- else if (GLYPHP (de->contents[elt]))
- {
- if (data->start_col)
- data->start_col--;
-
- if (!data->start_col && data->start_col_enabled)
- {
- prop = add_hscroll_rune (data);
- }
- else
- {
- struct glyph_block gb;
-
- gb.glyph = de->contents[elt];
- gb.extent = Qnil;
- prop = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
- }
- }
- else if (INTP (de->contents[elt]))
- {
- data->ch = XINT (de->contents[elt]);
- prop = add_emchar_rune (data);
- }
- /* Else blow it off because someone added a bad entry and we
- don't have any safe way of signaling an error. */
-
- /* #### Still need to add any remaining elements to the
- propagation information. */
- if (prop)
- return prop;
- }
- }
- else if (STRINGP (entry))
- {
- prop = add_string_of_bufbyte_runes (data,
- string_data (XSTRING (entry)),
- string_length (XSTRING (entry)),
- 0);
- }
- else if (GLYPHP (entry))
- {
- if (data->start_col)
- data->start_col--;
-
- if (!data->start_col && data->start_col_enabled)
- {
- prop = add_hscroll_rune (data);
- }
- else
- {
- struct glyph_block gb;
-
- gb.glyph = entry;
- gb.extent = Qnil;
- prop = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
- }
- }
- else if (INTP (entry))
- {
- data->ch = XINT (entry);
- prop = add_emchar_rune (data);
- }
-
- /* Else blow it off because someone added a bad entry and we don't
- have any safe way of signaling an error. Hey, this comment
- sounds familiar. */
- return prop;
- }
-
- /*****************************************************************************
- add_propagation_runes
-
- Add runes which were propagated from the previous line.
- ****************************************************************************/
- static prop_block_dynarr *
- add_propagation_runes (prop_block_dynarr **prop, pos_data *data)
- {
- /* #### Remember to handle start_col parameter of data when the rest of
- this is finished. */
- int elt;
- prop_block_dynarr *add_failed;
- Bufpos old_cursor_bufpos = data->cursor_bufpos;
- enum cursor_type old_cursor_type = data->cursor_type;
-
- for (elt = 0; elt < Dynarr_length (*prop); elt++)
- {
- struct prop_block *pb = Dynarr_atp (*prop, elt);
-
- switch (pb->type)
- {
- case PROP_CHAR:
- data->ch = pb->data.p_char.ch;
- data->cursor_bufpos = pb->data.p_char.cursor_bufpos;
- data->cursor_type = pb->data.p_char.cursor_type;
- add_failed = add_emchar_rune (data);
-
- if (add_failed)
- {
- if (elt == 0)
- {
- /* We didn't get anything added. This is virtually
- impossible. (Don't speak too fast -- Dubuque
- will proceed to produce a long list of "reasonable"
- cases where this would happen.) */
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- return *prop;
- }
- else
- {
- /* Move the remaing entries to the beginning of the
- array and return. */
- int end = Dynarr_length (*prop);
-
- Dynarr_reset (*prop);
- while (elt < end)
- Dynarr_add (*prop, Dynarr_at (*prop, elt));
-
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- return *prop;
- }
- }
- break;
- case PROP_STRING:
- if (pb->data.p_string.str)
- xfree (pb->data.p_string.str);
- /* #### bogus bogus -- this doesn't do anything!
- Should probably call add_string_of_bufbyte_runes(),
- once that function is fixed. */
- break;
- case PROP_MINIBUF_PROMPT:
- /* #### Hey, Ben! Does this need to probably be using a
- stream or some kind of accessor function to get the next
- character in order to make Mule work? */
- {
- face_index old_findex = data->findex;
- Bufpos old_bufpos = data->bufpos;
-
- data->findex = DEFAULT_INDEX;
- data->bufpos = 0;
- data->cursor_type = NO_CURSOR;
-
- while (pb->data.p_string.pos < pb->data.p_string.len)
- {
- data->ch = pb->data.p_string.str[pb->data.p_string.pos];
- add_failed = add_emchar_rune (data);
-
- if (add_failed)
- {
- data->findex = old_findex;
- data->bufpos = old_bufpos;
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- return *prop;
- }
- else
- pb->data.p_string.pos++;
- }
-
- data->findex = old_findex;
- /* ##### FIXME FIXME FIXME -- Upon successful return from
- this function, data->bufpos is automatically incremented.
- However, we don't want that to happen if we were adding
- the minibuffer prompt. */
- data->bufpos = old_bufpos - 1;
- }
- break;
- case PROP_BLANK:
- {
- int old_width = data->width;
- face_index old_findex = data->findex;
-
- data->findex = pb->data.p_blank.findex;
- data->width = pb->data.p_blank.width;
- data->cursor_bufpos = 0;
- data->cursor_type = IGNORE_CURSOR;
-
- if (data->pixpos + data->width > data->max_pixpos)
- data->width = data->max_pixpos - data->pixpos;
-
- /* We pass a bogus value of char_tab_width. It shouldn't
- matter because unless something is really screwed up
- this call won't cause that arg to be used. */
- add_failed = add_blank_rune (data, XWINDOW (data->window), 0);
-
- /* This can happen in the case where we have a tab which
- is wider than the window. */
- if (data->width != pb->data.p_blank.width)
- {
- pb->data.p_blank.width -= data->width;
- add_failed = ADD_FAILED;
- }
-
- data->findex = old_findex;
- data->width = old_width;
-
- if (add_failed)
- {
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- return *prop;
- }
- }
- break;
- default:
- abort ();
- }
- }
-
- Dynarr_free (*prop);
- data->cursor_bufpos = old_cursor_bufpos;
- data->cursor_type = old_cursor_type;
- return NULL;
- }
-
- /*****************************************************************************
- add_glyph_rune
-
- Add 'text layout glyphs at position POS_TYPE that are contained to
- the display block, but add all other types to the appropriate list of
- the display line. They will be added later by different routines.
- ****************************************************************************/
- static prop_block_dynarr *
- add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
- int allow_cursor, struct glyph_cache_element *inst)
- {
- struct window *w = XWINDOW (data->window);
-
- /* A nil extent indicates a special glyph (ex. truncator) */
- if (NILP (gb->extent)
- || (pos_type == BEGIN_GLYPHS &&
- extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT)
- || (pos_type == END_GLYPHS &&
- extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT))
- {
- struct rune rb;
- int width;
- int xoffset = 0;
- int ascent, descent;
- Lisp_Object baseline;
- Lisp_Object face;
-
- if (inst)
- width = inst->width;
- else
- width = glyph_width (gb->glyph, data->findex, 0, data->window);
-
- if (!width)
- return NULL;
-
- if (data->start_col)
- {
- prop_block_dynarr *retval;
- int glyph_char_width = width / space_width (w);
-
- /* If we still have not fully scrolled horizontally after
- taking into account the width of the glyph, subtract its
- width and return. */
- if (glyph_char_width < data->start_col)
- {
- data->start_col -= glyph_char_width;
- return NULL;
- }
- else if (glyph_char_width == data->start_col)
- width = 0;
- else
- {
- xoffset = space_width (w) * data->start_col;
- width -= xoffset;
-
- /* #### Can this happen? */
- if (width < 0)
- width = 0;
- }
-
- data->start_col = 0;
- retval = add_hscroll_rune (data);
-
- /* Could be caused by the handling of the hscroll rune. */
- if (retval != NULL || !width)
- return retval;
- }
- else
- xoffset = 0;
-
- if (data->pixpos + width > data->max_pixpos)
- {
- /* If this is the first object we are attempting to add to
- the line then we ignore the horizontal_clip threshold.
- Otherwise we will loop until the bottom of the window
- continually failing to add this glyph because it is wider
- than the window. We could alternatively just completely
- ignore the glyph and proceed from there but I think that
- this is a better solution. */
- if (Dynarr_length (data->db->runes)
- && data->max_pixpos - data->pixpos < horizontal_clip)
- return ADD_FAILED;
- else
- width = data->max_pixpos - data->pixpos;
- }
-
- if (inst)
- {
- ascent = inst->ascent;
- descent = inst->descent;
- }
- else
- {
- ascent = glyph_ascent (gb->glyph, data->findex, 0, data->window);
- descent = glyph_descent (gb->glyph, data->findex, 0, data->window);
- }
-
- baseline = glyph_baseline (gb->glyph, data->window);
-
- if (glyph_contrib_p (gb->glyph, data->window))
- {
- /* A pixmap that has not had a baseline explicitly set. Its
- contribution will be determined later. */
- if (NILP (baseline))
- {
- int height = ascent + descent;
- data->max_pixmap_height = max (data->max_pixmap_height, height);
- }
-
- /* A string so determine contribution normally. */
- else if (EQ (baseline, Qt))
- {
- data->new_ascent = max (data->new_ascent, ascent);
- data->new_descent = max (data->new_descent, descent);
- }
-
- /* A pixmap with an explicitly set baseline. We determine the
- contribution here. */
- else if (INTP (baseline))
- {
- int height = ascent + descent;
- int pix_ascent, pix_descent;
-
- pix_ascent = height * XINT (baseline) / 100;
- pix_descent = height - pix_ascent;
-
- data->new_ascent = max (data->new_ascent, pix_ascent);
- data->new_descent = max (data->new_descent, pix_descent);
- }
-
- /* Otherwise something is screwed up. */
- else
- abort ();
- }
-
- face = glyph_face (gb->glyph, data->window);
- if (NILP (face))
- rb.findex = data->findex;
- else
- rb.findex = get_builtin_face_cache_index (w, face);
-
- rb.extent = gb->extent;
- rb.xpos = data->pixpos;
- rb.width = width;
- rb.bufpos = 0; /* glyphs are never "at" anywhere */
- rb.endpos = data->endpos;
- rb.type = DGLYPH;
- /* #### Ben sez: this is way bogus if the glyph is a string.
- You should not make the output routines have to cope with
- this. The string could contain Mule characters, or non-
- printable characters, or characters to be passed through
- the display table, or non-character objects (when this gets
- implemented), etc. Instead, this routine here should parse
- the string into a series of runes. */
- rb.object.dglyph.glyph = gb->glyph;
- rb.object.dglyph.xoffset = xoffset;
-
- if (allow_cursor)
- {
- rb.bufpos = data->bufpos;
-
- if (data->cursor_type == CURSOR_ON)
- {
- if (data->bufpos == data->cursor_bufpos)
- {
- rb.cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- }
- else
- rb.cursor_type = CURSOR_OFF;
- }
- else if (data->cursor_type == NEXT_CURSOR)
- {
- rb.cursor_type = CURSOR_ON;
- data->cursor_x = Dynarr_length (data->db->runes);
- data->cursor_type = NO_CURSOR;
- }
- else if (data->cursor_type == IGNORE_CURSOR)
- rb.cursor_type = IGNORE_CURSOR;
- else if (data->cursor_type == NO_CURSOR)
- rb.cursor_type = NO_CURSOR;
- else
- rb.cursor_type = CURSOR_OFF;
- }
- else
- rb.cursor_type = CURSOR_OFF;
-
- Dynarr_add (data->db->runes, rb);
- data->pixpos += width;
-
- return NULL;
- }
- else
- {
- if (!NILP (glyph_face (gb->glyph, data->window)))
- gb->findex =
- get_builtin_face_cache_index (w, glyph_face (gb->glyph,
- data->window));
- else
- gb->findex = data->findex;
-
- if (pos_type == BEGIN_GLYPHS)
- {
- if (!data->dl->left_glyphs)
- data->dl->left_glyphs = Dynarr_new (struct glyph_block);
- Dynarr_add (data->dl->left_glyphs, *gb);
- return NULL;
- }
- else if (pos_type == END_GLYPHS)
- {
- if (!data->dl->right_glyphs)
- data->dl->right_glyphs = Dynarr_new (struct glyph_block);
- Dynarr_add (data->dl->right_glyphs, *gb);
- return NULL;
- }
- else
- abort (); /* there are no unknown types */
- }
-
- return NULL; /* shut up compiler */
- }
-
- /*****************************************************************************
- add_glyph_runes
-
- Add all glyphs at position POS_TYPE that are contained in the given
- data.
- ****************************************************************************/
- static prop_block_dynarr *
- add_glyph_runes (pos_data *data, int pos_type)
- {
- /* #### This still needs to handle the start_col parameter. Duh, Chuck,
- why didn't you just modify add_glyph_rune in the first place? */
- int elt;
- glyph_block_dynarr *glyph_arr = (pos_type == BEGIN_GLYPHS
- ? data->ef->begin_glyphs
- : data->ef->end_glyphs);
- prop_block_dynarr *prop;
-
- for (elt = 0; elt < Dynarr_length (glyph_arr); elt++)
- {
- prop = add_glyph_rune (data, Dynarr_atp (glyph_arr, elt), pos_type, 0,
- 0);
-
- if (prop)
- {
- /* #### Add some propagation information. */
- return prop;
- }
- }
-
- Dynarr_reset (glyph_arr);
-
- return NULL;
- }
-
- /*****************************************************************************
- create_text_block
-
- Given a position for a buffer in a window, ensure that the given
- display line DL accurately represents the text on a line starting at
- the given position.
- ****************************************************************************/
- static Bufpos
- create_text_block (struct window *w, struct display_line *dl, Bufpos start_pos,
- int start_col, prop_block_dynarr **prop, int type)
- {
- struct frame *f = XFRAME (w->frame);
- struct buffer *b = XBUFFER (w->buffer);
- struct device *d = XDEVICE (f->device);
-
- pos_data data;
- struct Lisp_Vector *dt = 0;
-
- /* Don't display anything in the minibuffer if this window is not on
- a selected frame. We consider all other windows to be active
- minibuffers as it simplifies the coding. */
- int active_minibuffer = (!MINI_WINDOW_P (w) ||
- (f == device_selected_frame (d)));
-
- int truncate_win = window_truncation_on (w);
- int end_glyph_width;
-
- /* If the buffer's value of selective_display is an integer then
- only lines that start with less than selective_display columns of
- space will be displayed. If selective_display is t then all text
- after a ^M is invisible. */
- int selective = (INTP (b->selective_display)
- ? XINT (b->selective_display)
- : ((!NILP (b->selective_display) ? -1 : 0)));
-
- /* The variable ctl-arrow allows the user to specify what characters
- can actually be displayed and which octal should be used for.
- #### This variable should probably have some rethought done to
- it.
-
- #### It would also be really nice if you could specify that
- the characters come out in hex instead of in octal. Mule
- does that by adding a ctl-hexa variable similar to ctl-arrow,
- but that's bogus -- we need a more general solution. I
- think you need to extend the concept of display tables
- into a more general conversion mechanism. Ideally you
- could specify a Lisp function that converts characters,
- but this violates the Second Golden Rule and besides would
- make things way way way way slow. An idea I like is to
- be able to specify multiple display tables instead of just
- one. Each display table can specify conversions for some
- characters and leave others unchanged. The way the
- character gets displayed is determined by the first display
- table with a binding for that character. This way, you
- could call a function `enable-hex-display' that adds a
- pre-defined hex display-table (or maybe computes one if
- you give weird parameters to the function) and adds it
- to the list of display tables for the current buffer.
-
- Unfortunately there are still problems dealing with Mule
- characters. For example, maybe I want to specify that
- all extended characters (i.e. >= 256) are displayed in hex.
- It's not reasonable to create a mapping for all possible
- such characters, because there are about 2^19 of them.
- One way of dealing with this is to extend the concept
- of what a display table is. Currently it's only allowed
- to be a 256-entry vector. Instead, it should be something
- like:
-
- a) A 256-entry vector, for backward compatibility
- b) Some sort of hashtable, mapping characters to values
- c) A list that specifies a range of values and the
- mapping to provide for those values.
-
- Also, extend the concept of "mapping" to include a
- printf-like spec. Then, you could make all extended
- characters show up as hex with a display table like
-
- ((256 . 524288) . "%x")
-
- Since more than one display table is possible, you have
- great flexibility in mapping ranges of characters.
- */
- Emchar printable_min = (INTP (b->ctl_arrow)
- ? XINT (b->ctl_arrow)
- : ((EQ (b->ctl_arrow, Qt) || EQ (b->ctl_arrow, Qnil))
- ? 255 : 160));
-
- /* The text display block for this display line. */
- struct display_block *db = get_display_block_from_line (dl, TEXT);
-
- /* The first time through the main loop we need to force the glyph
- data to be updated. */
- int initial = 1;
-
- /* Apparently the new extent_fragment_update returns an end position
- equal to the position passed in if there are no more runs to be
- displayed. */
- int no_more_frags = 0;
-
- dl->used_prop_data = 0;
- dl->num_chars = 0;
- data.ef = extent_fragment_new (b, f);
-
- /* These values are used by all of the rune addition routines. We add
- them to this structure for ease of passing. */
- data.d = d;
- XSETWINDOW (data.window, w);
- data.db = db;
- data.dl = dl;
-
- data.bufpos = start_pos;
- data.endpos = 0;
- data.pixpos = dl->bounds.left_in;
- data.new_ascent = data.new_descent = data.max_pixmap_height = 0;
- data.ch = '\0';
-
- /* Set the right boundary adjusting it to take into account any end
- glyph. Save the width of the end glyph for later use. */
- data.max_pixpos = dl->bounds.right_in;
- if (truncate_win)
- end_glyph_width = GLYPH_CACHE_ELEMENT_WIDTH (w, TRUN_GLYPH_INDEX);
- else
- end_glyph_width = GLYPH_CACHE_ELEMENT_WIDTH (w, CONT_GLYPH_INDEX);
- data.max_pixpos -= end_glyph_width;
-
- if (cursor_in_echo_area)
- {
- if (MINI_WINDOW_P (w) && echo_area_active (f))
- {
- data.cursor_bufpos = BUF_ZV (b);
- data.cursor_type = CURSOR_ON;
- }
- else
- data.cursor_type = NO_CURSOR;
- }
- else if (MINI_WINDOW_P (w) && !active_minibuffer)
- data.cursor_type = NO_CURSOR;
- else if (w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
- {
- data.cursor_bufpos = BUF_PT (b);
- data.cursor_type = CURSOR_ON;
- }
- else if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
- {
- data.cursor_bufpos = marker_position (w->pointm[type]);
- data.cursor_type = CURSOR_ON;
- }
- else
- data.cursor_type = NO_CURSOR;
- data.cursor_x = -1;
-
- data.start_col = w->hscroll;
- data.start_col_enabled = (w->hscroll ? start_pos : 0);
-
- /* We regenerate the line from the very beginning. */
- Dynarr_reset (db->runes);
-
- /* Why is this less than or equal and not just less than? If the
- starting position is already equal to the maximum we can't add
- anything else, right? Wrong. We might still have a newline to
- add. A newline can use the room allocated for an end glyph since
- if we add it we know we aren't going to be adding any end
- glyph. */
-
- /* #### Chuck -- I think this condition should be while (1).
- Otherwise if (e.g.) there is one begin-glyph and one end-glyph
- and the begin-glyph ends exactly at the end of the window, the
- end-glyph and text might not be displayed. while (1) ensures
- that the loop terminates only when either (a) there is
- propagation data or (b) the end-of-line or end-of-buffer is hit.
-
- #### Also I think you need to ensure that the operation
- "add begin glyphs; add end glyphs; add text" is atomic and
- can't get interrupted in the middle. If you run off the end
- of the line during that operation, then you keep accumulating
- propagation data until you're done. Otherwise, if the (e.g.)
- there's a begin glyph at a particular position and attempting
- to display that glyph results in window-end being hit and
- propagation data being generated, then the character at that
- position won't be displayed.
-
- #### See also the comment after the end of this loop, below.
- */
- while (data.pixpos <= data.max_pixpos
- && (active_minibuffer || !NILP (Vsynchronize_minibuffers)))
- {
- /* #### Currently this loop deals entirely in Bufpos's.
- It could probably be sped up (for Mule) by also
- keeping track of the current Bytind, to reduce the
- number of calls to bufpos_to_bytind(). (Remember,
- this call is made implicitly every time you call
- any of the BUF_* functions. The BI_BUF_* functions
- deal directly in Bytind's and thus do not need this
- extra call.) However, I don't want to worry about
- this right now. */
-
- /* #### This check probably should not be necessary. */
- if (data.bufpos > BUF_ZV (b))
- {
- data.bufpos--;
- goto done;
- }
-
- /* If selective display was an integer and we aren't working on
- a continuation line then find the next line we are actually
- supposed to display. */
- if (selective > 0
- && (data.bufpos == BUF_BEGV (b)
- || BUF_FETCH_CHAR (b, data.bufpos - 1) == '\n'))
- {
- while (spaces_at_point (b, data.bufpos) >= selective)
- {
- data.bufpos = find_next_newline_no_quit (b, data.bufpos, 1);
- if (data.bufpos >= BUF_ZV (b))
- {
- data.bufpos = BUF_ZV (b);
- goto done;
- }
- }
- }
-
- /* Check for face changes. */
- if (initial || (!no_more_frags &&
- data.bufpos == bytind_to_bufpos (b, data.ef->end)))
- {
- /* Now compute the face and begin/end-glyph information. */
- data.findex =
- extent_fragment_update (w, data.ef,
- /* Remember that the extent-fragment
- routines deal in Bytind's. This
- should perhaps be changed, for
- consistency. */
- bufpos_to_bytind (b, data.bufpos));
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT (w, data.findex), &data.fm));
-
- if (data.bufpos == bytind_to_bufpos (b, data.ef->end))
- no_more_frags = 1;
-
- dt = get_display_table (w, data.findex);
- data.new_ascent = max (data.new_ascent, data.fm.ascent);
- data.new_descent = max (data.new_descent, data.fm.descent);
-
- /* It can be expensive to call the text width routines. If
- the font we are currently working with is not
- proportional, we'll pass along the character width so that
- the addition subroutines don't need to calculate it. */
- if (data.fm.proportional)
- data.width = 0;
- else
- data.width = data.fm.width;
- }
- initial = 0;
-
- /* Determine what is next to be displayed. We first handle any
- glyphs returned by glyphs_at_bufpos. If there are no glyphs to
- display then we determine what to do based on the character at the
- current buffer position. */
-
- /* If the current position is covered by an invisible extent, do
- nothing.
-
- #### The behavior of begin and end-glyphs at the edge of an
- invisible extent should be investigated further. This is
- fairly low priority though. */
- if (data.ef->invisible)
- {
- if (*prop)
- Dynarr_free (*prop);
-
- /* If point is in an invisible region we place it on the
- next visible character. */
- if (data.cursor_type == CURSOR_ON
- && data.bufpos == data.cursor_bufpos)
- {
- data.cursor_type = NEXT_CURSOR;
- }
-
- /* #### What if we we're dealing with a display table? */
- if (data.start_col)
- data.start_col--;
-
- if (data.bufpos == BUF_ZV (b))
- goto done;
- else
- data.bufpos++;
- }
-
- /* If there is propagation data, then it represents the current
- buffer position being displayed. Add them and advance the
- position counter. This might also add the minibuffer
- prompt. */
- else if (*prop)
- {
- dl->used_prop_data = 1;
- *prop = add_propagation_runes (prop, &data);
-
- if (*prop)
- goto done; /* gee, a really narrow window */
- else if (data.bufpos == BUF_ZV (b))
- goto done;
- else
- data.bufpos++;
- }
-
- /* If there are end glyphs, add them to the line. These are
- the end glyphs for the previous run of text. We add them
- here rather than doing them at the end of handling the
- previous run so that glyphs at the beginning and end of
- a line are handled correctly. */
- else if (Dynarr_length (data.ef->end_glyphs) > 0)
- {
- *prop = add_glyph_runes (&data, END_GLYPHS);
- if (*prop)
- goto done;
- }
-
- /* If there are begin glyphs, add them to the line. */
- else if (Dynarr_length (data.ef->begin_glyphs) > 0)
- {
- *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
- if (*prop)
- goto done;
- }
-
- /* If at end-of-buffer, we've already processed begin and
- end-glyphs at this point and there's no text to process,
- so we're done. */
- else if (data.bufpos == BUF_ZV (b))
- goto done;
-
- else
- {
- /* Get the character at the current buffer position. */
- data.ch = BUF_FETCH_CHAR (b, data.bufpos);
-
- /* If there is a display table entry for it, hand it off to
- add_disp_table_entry_runes and let it worry about it. */
- if (dt && !NILP (DISP_CHAR_ENTRY (dt, data.ch)))
- {
- *prop =
- add_disp_table_entry_runes (&data,
- DISP_CHAR_ENTRY (dt, data.ch));
-
- if (*prop)
- goto done;
- }
-
- /* Check if we have hit a newline character. If so, add a marker
- to the line and end this loop. */
- else if (data.ch == '\n')
- {
- /* We aren't going to be adding an end glyph so give its
- space back in order to make sure that the cursor can
- fit. */
- data.max_pixpos += end_glyph_width;
-
- if (selective > 0
- && (spaces_at_point (b, data.bufpos + 1) >= selective))
- {
- /* We won't be adding a truncation or continuation glyph
- so give up the room allocated for them. */
- data.max_pixpos += end_glyph_width;
-
- if (!NILP (b->selective_display_ellipses))
- {
- struct glyph_block gb;
-
- gb.extent = Qnil;
- gb.glyph = Vinvisible_text_glyph;
- add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0,
- GLYPH_CACHE_ELEMENT (w, INVIS_GLYPH_INDEX));
- }
- else
- {
- data.width = DEVMETH (d, eol_cursor_width, ());
- *prop = add_emchar_rune (&data);
- }
-
- /* We need to set data.bufpos to the start of the
- next visible region in order to make this line
- appear to contain all of the invisible area.
- Otherwise, the line cache won't work
- correctly. */
- data.bufpos++;
- while (spaces_at_point (b, data.bufpos) >= selective)
- {
- data.bufpos = find_next_newline_no_quit (b, data.bufpos,
- 1);
- if (data.bufpos >= BUF_ZV (b))
- {
- data.bufpos = BUF_ZV (b);
- break;
- }
- }
- if (BUF_FETCH_CHAR (b, data.bufpos - 1) == '\n')
- data.bufpos--;
- }
- else
- {
- data.width = DEVMETH (d, eol_cursor_width, ());
- *prop = add_emchar_rune (&data);
- }
-
- goto done;
- }
-
- /* If the current character is ^M, and selective display is
- enabled, then add the invisible-text-glyph if
- selective-display-ellipses is set. In any case, this
- line is done. */
- else if (data.ch == (('M' & 037)) && selective == -1)
- {
- Bufpos next_bufpos;
-
- /* Find the buffer position at the end of the line. */
- next_bufpos = find_next_newline_no_quit (b, data.bufpos, 1);
- if (BUF_FETCH_CHAR (b, next_bufpos - 1) == '\n')
- next_bufpos--;
-
- /* If the cursor is somewhere in the elided text make
- sure that the cursor gets drawn appropriately. */
- if (data.cursor_type == CURSOR_ON
- && (data.cursor_bufpos >= data.bufpos &&
- data.cursor_bufpos < next_bufpos))
- {
- data.cursor_type = NEXT_CURSOR;
- }
-
- /* We won't be adding a truncation or continuation glyph
- so give up the room allocated for them. */
- data.max_pixpos += end_glyph_width;
-
- if (!NILP (b->selective_display_ellipses))
- {
- /* We don't propagate anything from the invisible
- text glyph if it fails to fit. This is
- intentional. */
- struct glyph_block gb;
-
- gb.extent = Qnil;
- gb.glyph = Vinvisible_text_glyph;
- add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 1,
- GLYPH_CACHE_ELEMENT (w, INVIS_GLYPH_INDEX));
- }
-
- /* Set the buffer position to the end of the line. We
- need to do this before potentially adding a newline
- so that the cursor flag will get set correctly (if
- needed). */
- data.bufpos = next_bufpos;
-
- if (NILP (b->selective_display_ellipses)
- || data.cursor_bufpos == next_bufpos)
- {
- /* We have to at least add a newline character so
- that the cursor shows up properly. */
- data.ch = '\n';
- data.width = DEVMETH (d, eol_cursor_width, ());
- data.findex = DEFAULT_INDEX;
- data.start_col = 0;
- data.start_col_enabled = 0;
-
- add_emchar_rune (&data);
- }
-
- /* This had better be a newline but doing it this way
- we'll see obvious incorrect results if it isn't. No
- need to abort here. */
- data.ch = BUF_FETCH_CHAR (b, data.bufpos);
-
- goto done;
- }
-
- /* If the current character is considered to be printable, then
- just add it. */
- else if (data.ch >= printable_min)
- {
- *prop = add_emchar_rune (&data);
- if (*prop)
- goto done;
- }
-
- /* If the current character is a tab, determine the next tab
- starting position and add a blank rune which extends from the
- current pixel position to that starting position. */
- else if (data.ch == '\t')
- {
- int old_width = data.width;
- int tab_start_pixpos = data.pixpos;
- int next_tab_start;
- int char_tab_width;
- int prop_width = 0;
-
- if (data.start_col > 1)
- tab_start_pixpos -= (space_width (w) * (data.start_col - 1));
-
- next_tab_start = next_tab_position (w, tab_start_pixpos,
- dl->bounds.left_in);
- if (next_tab_start > data.max_pixpos)
- {
- prop_width = next_tab_start - data.max_pixpos;
- next_tab_start = data.max_pixpos;
- }
- data.width = next_tab_start - data.pixpos;
- char_tab_width =
- (next_tab_start - tab_start_pixpos) / space_width (w);
-
- *prop = add_blank_rune (&data, w, char_tab_width);
- data.width = old_width;
-
- /* add_blank_rune is only supposed to be called with
- sizes guaranteed to fit in the available space. */
- assert (!(*prop));
-
- if (prop_width)
- {
- struct prop_block pb;
- *prop = Dynarr_new (struct prop_block);
-
- pb.type = PROP_BLANK;
- pb.data.p_blank.width = prop_width;
- pb.data.p_blank.findex = data.findex;
- Dynarr_add (*prop, pb);
-
- goto done;
- }
- }
-
- /* If character is a control character, pass it off to
- add_control_char_runes.
-
- The is_*() routines have undefined results on
- arguments outside of the range [-1, 255]. (This
- often bites people who carelessly use `char' instead
- of `unsigned char'.)
- */
- else if (data.ch < 0x100 && iscntrl ((Bufbyte) data.ch))
- {
- *prop = add_control_char_runes (&data, b);
-
- if (*prop)
- goto done;
- }
-
- /* If the character is above the ASCII range and we have not
- already handled it, then print it as an octal number. */
- else if (data.ch >= 0200)
- {
- *prop = add_octal_runes (&data);
-
- if (*prop)
- goto done;
- }
-
- /* Assume the current character is considered to be printable,
- then just add it. */
- else
- {
- *prop = add_emchar_rune (&data);
- if (*prop)
- goto done;
- }
-
- data.bufpos++;
- }
- }
-
- done:
-
- /* Determine the starting point of the next line if we did not hit the
- end of the buffer. */
- if (data.bufpos < BUF_ZV (b)
- && (active_minibuffer || !NILP (Vsynchronize_minibuffers)))
- {
- /* #### This check is not correct. If the line terminated
- due to a begin-glyph or end-glyph hitting window-end, then
- data.ch will not point to the character at data.bufpos. If
- you make the two changes mentioned at the top of this loop,
- you should be able to say '(if (*prop))'. That should also
- make it possible to eliminate the data.bufpos < BUF_ZV (b)
- check. */
-
- /* The common case is that the line ended because we hit a newline.
- In that case, the next character is just the next buffer
- position. */
- if (data.ch == '\n')
- {
- /* If data.start_col_enabled is still true, then the window is
- scrolled far enough so that nothing on this line is visible.
- We need to stick a trunctation glyph at the beginning of the
- line in that case unless the line is completely blank. */
- if (data.start_col_enabled)
- {
- if (data.cursor_type == CURSOR_ON)
- {
- if (data.cursor_bufpos >= start_pos
- && data.cursor_bufpos <= data.bufpos)
- data.cursor_bufpos = data.bufpos;
- }
- data.findex = DEFAULT_INDEX;
- data.start_col = 0;
- data.start_col_enabled = 0;
-
- if (data.bufpos != start_pos)
- {
- struct glyph_block gb;
-
- gb.extent = Qnil;
- gb.glyph = Vhscroll_glyph;
- add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0,
- GLYPH_CACHE_ELEMENT (w, HSCROLL_GLYPH_INDEX));
- }
- else
- {
- /* This duplicates code down below to add a newline to
- the end of an otherwise empty line.*/
- data.ch = '\n';
- data.width = DEVMETH (d, eol_cursor_width, ());
-
- add_emchar_rune (&data);
- }
- }
-
- data.bufpos++;
- }
-
- /* Otherwise we have a buffer line which cannot fit on one display
- line. */
- else
- {
- struct glyph_block gb;
- struct glyph_cache_element *inst;
-
- /* If the line is to be truncated then we actually have to look
- for the next newline. We also add the end-of-line glyph which
- we know will fit because we adjusted the right border before
- we starting laying out the line. */
- data.max_pixpos += end_glyph_width;
- data.findex = DEFAULT_INDEX;
- gb.extent = Qnil;
-
- if (truncate_win)
- {
- Bufpos pos;
-
- /* Now find the start of the next line. */
- pos = find_next_newline_no_quit (b, data.bufpos, 1);
-
- /* If the cursor is past the truncation line then we
- make it appear on the truncation glyph. If we've hit
- the end of the buffer then we also make the cursor
- appear unless eob is immediately preceeded by a
- newline. In that case the cursor should actually
- appear on the next line. */
- if (data.cursor_type == CURSOR_ON
- && data.cursor_bufpos >= data.bufpos
- && (data.cursor_bufpos < pos ||
- (pos == BUF_ZV (b)
- && (pos == BUF_BEGV (b)
- || BUF_FETCH_CHAR (b, pos - 1) != '\n'))))
- data.cursor_bufpos = pos;
- else
- data.cursor_type = NO_CURSOR;
-
- data.bufpos = pos;
- gb.glyph = Vtruncation_glyph;
- inst = GLYPH_CACHE_ELEMENT (w, TRUN_GLYPH_INDEX);
- }
- else
- {
- /* The cursor can never be on the continuation glyph. */
- data.cursor_type = NO_CURSOR;
-
- /* data.bufpos is already at the start of the next line. */
-
- gb.glyph = Vcontinuation_glyph;
- inst = GLYPH_CACHE_ELEMENT (w, CONT_GLYPH_INDEX);
- }
-
- add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 1, inst);
-
- if (truncate_win && data.bufpos == BUF_ZV (b)
- && BUF_FETCH_CHAR (b, BUF_ZV (b) - 1) != '\n')
- data.bufpos++;
- }
- }
- else if ((active_minibuffer || !NILP (Vsynchronize_minibuffers))
- && (!echo_area_active (f) || data.bufpos == BUF_ZV (b)))
- {
- /* We need to add a marker to the end of the line since there is no
- newline character in order for the cursor to get drawn. We label
- it as a newline so that it gets handled correctly by the
- whitespace routines below. */
-
- data.ch = '\n';
- data.width = DEVMETH (d, eol_cursor_width, ());
- data.findex = DEFAULT_INDEX;
- data.start_col = 0;
- data.start_col_enabled = 0;
-
- data.max_pixpos += data.width;
- add_emchar_rune (&data);
- data.max_pixpos -= data.width;
-
- data.bufpos = BUF_ZV (b) + 1;
- }
-
- /* Calculate left whitespace boundary. */
- {
- int elt = 0;
-
- /* Whitespace past a newline is considered right whitespace. */
- while (elt < Dynarr_length (db->runes))
- {
- struct rune *rb = Dynarr_atp (db->runes, elt);
-
- if ((rb->type == CHAR && rb->object.ch == ' ') || rb->type == BLANK)
- {
- dl->bounds.left_white += rb->width;
- elt++;
- }
- else
- elt = Dynarr_length (db->runes);
- }
- }
-
- /* Calculate right whitespace boundary. */
- {
- int elt = Dynarr_length (db->runes) - 1;
- int done = 0;
-
- while (!done && elt >= 0)
- {
- struct rune *rb = Dynarr_atp (db->runes, elt);
-
- if (!(rb->type == CHAR && isspace (rb->object.ch))
- && !rb->type == BLANK)
- {
- dl->bounds.right_white = rb->xpos + rb->width;
- done = 1;
- }
-
- elt--;
-
- }
-
- /* The line is blank so everything is considered to be right
- whitespace. */
- if (!done)
- dl->bounds.right_white = dl->bounds.left_in;
- }
-
- /* Set the display blocks bounds. */
- db->start_pos = dl->bounds.left_in;
- if (Dynarr_length (db->runes))
- {
- struct rune *rb = Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-
- db->end_pos = rb->xpos + rb->width;
- }
- else
- db->end_pos = dl->bounds.right_white;
-
- /* update line height parameters */
- if (!data.new_ascent && !data.new_descent)
- {
- /* We've got a blank line so initialize these values from the default
- face. */
- struct font_metric_info fm;
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
-
- data.new_ascent = fm.ascent;
- data.new_descent = fm.descent;
- }
-
- if (data.max_pixmap_height)
- {
- int height = data.new_ascent + data.new_descent;
- int pix_ascent, pix_descent;
-
- pix_descent = data.max_pixmap_height * data.new_descent / height;
- pix_ascent = data.max_pixmap_height - pix_descent;
-
- data.new_ascent = max (data.new_ascent, pix_ascent);
- data.new_descent = max (data.new_descent, pix_descent);
- }
-
- dl->ascent = data.new_ascent;
- dl->descent = data.new_descent;
-
- {
- unsigned short ascent = (unsigned short) XINT (w->minimum_line_ascent);
-
- if (dl->ascent < ascent)
- dl->ascent = ascent;
- }
- {
- unsigned short descent = (unsigned short) XINT (w->minimum_line_descent);
-
- if (dl->descent < descent)
- dl->descent = descent;
- }
-
- dl->cursor_elt = data.cursor_x;
- dl->end_bufpos = data.bufpos - 1;
- if (truncate_win)
- data.dl->num_chars = column_at_point (b, dl->end_bufpos, 0);
- else
- /* This doesn't correctly take into account tabs and control
- characters but if the window isn't being truncated then this
- value isn't going to end up being used anyhow. */
- data.dl->num_chars = dl->end_bufpos - dl->bufpos;
-
- /* #### handle horizontally scrolled line with text none of which
- was actually laid out. */
-
- /* #### handle any remainder of overlay arrow */
-
- if (*prop == ADD_FAILED)
- *prop = NULL;
-
- extent_fragment_delete (data.ef);
-
- /* #### If we started at EOB, then make sure we return a value past
- it so that regenerate_window will exit properly. This is bogus.
- The main loop should get fixed so that it isn't necessary to call
- this function if we are already at EOB. */
-
- if (data.bufpos == BUF_ZV (b) && start_pos == BUF_ZV (b))
- return (data.bufpos + 1);
- else
- return data.bufpos;
- }
-
- /*****************************************************************************
- create_overlay_glyph_block
-
- Display the overlay arrow at the beginning of the given line.
- ****************************************************************************/
- static int
- create_overlay_glyph_block (struct window *w, struct display_line *dl)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- pos_data data;
-
- /* If Voverlay_arrow_string isn't valid then just fail silently. */
- if (!STRINGP (Voverlay_arrow_string) && !GLYPHP (Voverlay_arrow_string))
- return 0;
-
- data.ef = NULL;
- data.d = d;
- XSETWINDOW (data.window, w);
- data.db = get_display_block_from_line (dl, OVERWRITE);
- data.dl = dl;
- data.bufpos = 0;
- data.endpos = 0;
- data.pixpos = dl->bounds.left_in;
- data.max_pixmap_height = 0;
- data.max_pixpos = dl->bounds.right_in;
- data.cursor_type = NO_CURSOR;
- data.cursor_x = -1;
- data.start_col = 0;
- data.start_col_enabled = 0;
- data.findex = DEFAULT_INDEX;
-
- DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, data.findex),
- &data.fm));
- data.new_ascent = max ((int) dl->ascent, data.fm.ascent);
- data.new_descent = max ((int) dl->descent, data.fm.descent);
- if (data.fm.proportional)
- data.width = 0;
- else
- data.width = data.fm.width;
-
- Dynarr_reset (data.db->runes);
-
- if (STRINGP (Voverlay_arrow_string))
- {
- add_string_of_bufbyte_runes
- (&data,
- string_data (XSTRING (Voverlay_arrow_string)),
- string_length (XSTRING (Voverlay_arrow_string)),
- 1);
- }
- else if (GLYPHP (Voverlay_arrow_string))
- {
- struct glyph_block gb;
-
- gb.glyph = Voverlay_arrow_string;
- gb.extent = Qnil;
- add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, 0);
- }
-
- if (data.max_pixmap_height)
- {
- int height = data.new_ascent + data.new_descent;
- int pix_ascent, pix_descent;
-
- pix_descent = data.max_pixmap_height * data.new_descent / height;
- pix_ascent = data.max_pixmap_height - pix_descent;
-
- data.new_ascent = max (data.new_ascent, pix_ascent);
- data.new_descent = max (data.new_descent, pix_descent);
- }
-
- dl->ascent = data.new_ascent;
- dl->descent = data.new_descent;
-
- data.db->start_pos = dl->bounds.left_in;
- data.db->end_pos = data.pixpos;
-
- return (data.pixpos - dl->bounds.left_in);
- }
-
- /*****************************************************************************
- add_margin_runes
-
- Add a type of glyph to a margin display block.
- ****************************************************************************/
- static int
- add_margin_runes (struct display_line *dl, struct display_block *db, int start,
- int count, int glyph_type, int side, Lisp_Object window)
- {
- glyph_block_dynarr *gbd = (side == LEFT_GLYPHS
- ? dl->left_glyphs
- : dl->right_glyphs);
- int elt, end;
- int xpos = start;
- int reverse;
-
- if ((glyph_type == GL_WHITESPACE && side == LEFT_GLYPHS)
- || (glyph_type == GL_INSIDE_MARGIN && side == RIGHT_GLYPHS))
- {
- reverse = 1;
- elt = Dynarr_length (gbd) - 1;
- end = 0;
- }
- else
- {
- reverse = 0;
- elt = 0;
- end = Dynarr_length (gbd);
- }
-
- while (count && ((!reverse && elt < end) || (reverse && elt >= end)))
- {
- struct glyph_block *gb = Dynarr_atp (gbd, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (gb->active &&
- ((side == LEFT_GLYPHS &&
- extent_begin_glyph_layout (XEXTENT (gb->extent)) == glyph_type)
- || (side == RIGHT_GLYPHS &&
- extent_end_glyph_layout (XEXTENT (gb->extent)) == glyph_type)))
- {
- struct rune rb;
-
- rb.width = gb->width;
- rb.findex = gb->findex;
- rb.extent = gb->extent;
- rb.xpos = xpos;
- rb.bufpos = -1;
- rb.endpos = 0;
- rb.type = DGLYPH;
- rb.object.dglyph.glyph = gb->glyph;
- rb.object.dglyph.xoffset = 0;
- rb.cursor_type = CURSOR_OFF;
-
- Dynarr_add (db->runes, rb);
- xpos += rb.width;
- count--;
- gb->active = 0;
-
- if (glyph_contrib_p (gb->glyph, window))
- {
- unsigned short ascent, descent;
- Lisp_Object baseline = glyph_baseline (gb->glyph, window);
-
- ascent = glyph_ascent (gb->glyph, gb->findex, 0, window);
- descent = glyph_descent (gb->glyph, gb->findex, 0, window);
-
- /* A pixmap that has not had a baseline explicitly set.
- We use the existing ascent / descent ratio of the
- line. */
- if (NILP (baseline))
- {
- int gheight = ascent + descent;
- int line_height = dl->ascent + dl->descent;
- int pix_ascent, pix_descent;
-
- pix_descent = (int) (gheight * dl->descent) / line_height;
- pix_ascent = gheight - pix_descent;
-
- dl->ascent = max ((int) dl->ascent, pix_ascent);
- dl->descent = max ((int) dl->descent, pix_descent);
- }
-
- /* A string so determine contribution normally. */
- else if (EQ (baseline, Qt))
- {
- dl->ascent = max (dl->ascent, ascent);
- dl->descent = max (dl->descent, descent);
- }
-
- /* A pixmap with an explicitly set baseline. We determine the
- contribution here. */
- else if (INTP (baseline))
- {
- int height = ascent + descent;
- int pix_ascent, pix_descent;
-
- pix_ascent = height * XINT (baseline) / 100;
- pix_descent = height - pix_ascent;
-
- dl->ascent = max ((int) dl->ascent, pix_ascent);
- dl->descent = max ((int) dl->descent, pix_descent);
- }
-
- /* Otherwise something is screwed up. */
- else
- abort ();
- }
- }
-
- (reverse ? elt-- : elt++);
- }
-
- return xpos;
- }
-
- /*****************************************************************************
- add_margin_blank
-
- Add a blank to a margin display block.
- ****************************************************************************/
- static void
- add_margin_blank (struct display_line *dl, struct display_block *db,
- struct window *w, int xpos, int width, int side)
- {
- struct rune rb;
-
- rb.findex = (side == LEFT_GLYPHS
- ? get_builtin_face_cache_index (w, Vleft_margin_face)
- : get_builtin_face_cache_index (w, Vright_margin_face));
- rb.extent = Qnil;
- rb.xpos = xpos;
- rb.width = width;
- rb.bufpos = -1;
- rb.endpos = 0;
- rb.type = BLANK;
- rb.cursor_type = CURSOR_OFF;
-
- Dynarr_add (db->runes, rb);
- }
-
- /*****************************************************************************
- create_left_glyph_block
-
- Display glyphs in the left outside margin, left inside margin and
- left whitespace area.
- ****************************************************************************/
- static void
- create_left_glyph_block (struct window *w, struct display_line *dl,
- int overlay_width)
- {
- Lisp_Object window;
-
- int use_overflow = (NILP (w->use_left_overflow) ? 0 : 1);
- int elt, end_xpos;
- int out_end, in_out_start, in_in_end, white_out_start, white_in_start;
- int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
- int left_in_start = dl->bounds.left_in;
- int left_in_end = dl->bounds.left_in + overlay_width;
-
- struct display_block *odb, *idb;
-
- XSETWINDOW (window, w);
-
- /* We have to add the glyphs to the line in the order outside,
- inside, whitespace. However the precedence dictates that we
- determine how many will fit in the reverse order. */
-
- /* Determine how many whitespace glyphs we can display and where
- they should start. */
- white_in_start = dl->bounds.left_white;
- white_out_start = left_in_start;
- white_out_cnt = white_in_cnt = 0;
- elt = 0;
-
- while (elt < Dynarr_length (dl->left_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
- {
- int width;
-
- width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (white_in_start - width >= left_in_end)
- {
- white_in_cnt++;
- white_in_start -= width;
- gb->width = width;
- gb->active = 1;
- }
- else if (use_overflow
- && (white_out_start - width > dl->bounds.left_out))
- {
- white_out_cnt++;
- white_out_start -= width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
-
- /* Determine how many inside margin glyphs we can display and where
- they should start. The inside margin glyphs get whatever space
- is left after the whitespace glyphs have been displayed. These
- are tricky to calculate since if we decide to use the overflow
- area we basicaly have to start over. So for these we build up a
- list of just the inside margin glyphs and manipulate it to
- determine the needed info. */
- {
- glyph_block_dynarr *ib;
- int avail_in, avail_out;
- int done = 0;
- int marker = 0;
- int used_in, used_out;
-
- elt = 0;
- used_in = used_out = 0;
- ib = Dynarr_new (struct glyph_block);
- while (elt < Dynarr_length (dl->left_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
- GL_INSIDE_MARGIN)
- {
- gb->width = glyph_width (gb->glyph, gb->findex, 0, window);
- used_in += gb->width;
- Dynarr_add (ib, *gb);
- }
-
- elt++;
- }
-
- if (white_out_cnt)
- avail_in = 0;
- else
- {
- avail_in = white_in_start - left_in_end;
- if (avail_in < 0)
- avail_in = 0;
- }
-
- if (!use_overflow)
- avail_out = 0;
- else
- avail_out = white_out_start - dl->bounds.left_out;
-
- marker = 0;
- while (!done && marker < Dynarr_length (ib))
- {
- int width = Dynarr_atp (ib, marker)->width;
-
- /* If everything now fits in the available inside margin
- space, we're done. */
- if (used_in <= avail_in)
- done = 1;
- else
- {
- /* Otherwise see if we have room to move a glyph to the
- outside. */
- if (used_out + width <= avail_out)
- {
- used_out += width;
- used_in -= width;
- }
- else
- done = 1;
- }
-
- if (!done)
- marker++;
- }
-
- /* At this point we now know that everything from marker on goes in
- the inside margin and everything before it goes in the outside
- margin. The stuff going into the outside margin is guaranteed
- to fit, but we may have to trim some stuff from the inside. */
-
- in_in_end = left_in_end;
- in_out_start = white_out_start;
- in_out_cnt = in_in_cnt = 0;
-
- Dynarr_free (ib);
- elt = 0;
- while (elt < Dynarr_length (dl->left_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
- GL_INSIDE_MARGIN)
- {
- int width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (used_out)
- {
- in_out_cnt++;
- in_out_start -= width;
- gb->width = width;
- gb->active = 1;
- used_out -= width;
- }
- else if (in_in_end + width < white_in_start)
- {
- in_in_cnt++;
- in_in_end += width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
- }
-
- /* Determine how many outside margin glyphs we can display. They
- always start at the left outside margin and can only use the
- outside margin space. */
- out_end = dl->bounds.left_out;
- out_cnt = 0;
- elt = 0;
-
- while (elt < Dynarr_length (dl->left_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have beeb handled in add_glyph_rune */
-
- if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
- GL_OUTSIDE_MARGIN)
- {
- int width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (out_end + width < in_out_start)
- {
- out_cnt++;
- out_end += width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
-
- /* Now that we now where everything goes, we add the glyphs as runes
- to the appropriate display blocks. */
- if (out_cnt || in_out_cnt || white_out_cnt)
- {
- odb = get_display_block_from_line (dl, LEFT_OUTSIDE_MARGIN);
- odb->start_pos = dl->bounds.left_out;
- /* #### We should stop adding a blank to account for the space
- between the end of the glyphs and the margin and instead set
- this accordingly. */
- odb->end_pos = dl->bounds.left_in;
- Dynarr_reset (odb->runes);
- }
- else
- odb = 0;
-
- if (in_in_cnt || white_in_cnt)
- {
- idb = get_display_block_from_line (dl, LEFT_INSIDE_MARGIN);
- idb->start_pos = dl->bounds.left_in;
- /* #### See above comment for odb->end_pos */
- idb->end_pos = dl->bounds.left_white;
- Dynarr_reset (idb->runes);
- }
- else
- idb = 0;
-
- /* First add the outside margin glyphs. */
- if (out_cnt)
- end_xpos = add_margin_runes (dl, odb, dl->bounds.left_out, out_cnt,
- GL_OUTSIDE_MARGIN, LEFT_GLYPHS, window);
- else
- end_xpos = dl->bounds.left_out;
-
- /* There may be blank space between the outside margin glyphs and
- the inside margin glyphs. If so, add a blank. */
- if (in_out_cnt && (in_out_start - end_xpos))
- {
- add_margin_blank (dl, odb, w, end_xpos, in_out_start - end_xpos,
- LEFT_GLYPHS);
- }
-
- /* Next add the inside margin glyphs which are actually in the
- outside margin. */
- if (in_out_cnt)
- {
- end_xpos = add_margin_runes (dl, odb, in_out_start, in_out_cnt,
- GL_INSIDE_MARGIN, LEFT_GLYPHS, window);
- }
-
- /* If we didn't add any inside margin glyphs to the outside margin,
- but are adding whitespace glyphs, then we need to add a blank
- here. */
- if (!in_out_cnt && white_out_cnt && (white_out_start - end_xpos))
- {
- add_margin_blank (dl, odb, w, end_xpos, white_out_start - end_xpos,
- LEFT_GLYPHS);
- }
-
- /* Next add the whitespace margin glyphs which are actually in the
- outside margin. */
- if (white_out_cnt)
- {
- end_xpos = add_margin_runes (dl, odb, white_out_start, white_out_cnt,
- GL_WHITESPACE, LEFT_GLYPHS, window);
- }
-
- /* We take care of clearing between the end of the glyphs and the
- start of the inside margin for lines which have glyphs. */
- if (odb && (left_in_start - end_xpos))
- {
- add_margin_blank (dl, odb, w, end_xpos, left_in_start - end_xpos,
- LEFT_GLYPHS);
- }
-
- /* Next add the inside margin glyphs which are actually in the
- inside margin. */
- if (in_in_cnt)
- {
- end_xpos = add_margin_runes (dl, idb, left_in_end, in_in_cnt,
- GL_INSIDE_MARGIN, LEFT_GLYPHS, window);
- }
- else
- end_xpos = left_in_end;
-
- /* Make sure that the area between the end of the inside margin
- glyphs and the whitespace glyphs is cleared. */
- if (idb && (white_in_start - end_xpos > 0))
- {
- add_margin_blank (dl, idb, w, end_xpos, white_in_start - end_xpos,
- LEFT_GLYPHS);
- }
-
- /* Next add the whitespace margin glyphs which are actually in the
- inside margin. */
- if (white_in_cnt)
- {
- add_margin_runes (dl, idb, white_in_start, white_in_cnt, GL_WHITESPACE,
- LEFT_GLYPHS, window);
- }
-
- /* Whitespace glyphs always end right next to the text block so
- there is nothing we have to make sure is cleared after them. */
- }
-
- /*****************************************************************************
- create_right_glyph_block
-
- Display glyphs in the right outside margin, right inside margin and
- right whitespace area.
- ****************************************************************************/
- static void
- create_right_glyph_block (struct window *w, struct display_line *dl)
- {
- Lisp_Object window;
-
- int use_overflow = (NILP (w->use_right_overflow) ? 0 : 1);
- int elt, end_xpos;
- int out_start, in_out_end, in_in_start, white_out_end, white_in_end;
- int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
-
- struct display_block *odb, *idb;
-
- XSETWINDOW (window, w);
-
- /* We have to add the glyphs to the line in the order outside,
- inside, whitespace. However the precedence dictates that we
- determine how many will fit in the reverse order. */
-
- /* Determine how many whitespace glyphs we can display and where
- they should start. */
- white_in_end = dl->bounds.right_white;
- white_out_end = dl->bounds.right_in;
- white_out_cnt = white_in_cnt = 0;
- elt = 0;
-
- while (elt < Dynarr_length (dl->right_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
- {
- int width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (white_in_end + width <= dl->bounds.right_in)
- {
- white_in_cnt++;
- white_in_end += width;
- gb->width = width;
- gb->active = 1;
- }
- else if (use_overflow
- && (white_out_end + width <= dl->bounds.right_out))
- {
- white_out_cnt++;
- white_out_end += width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
-
- /* Determine how many inside margin glyphs we can display and where
- they should start. The inside margin glyphs get whatever space
- is left after the whitespace glyphs have been displayed. These
- are tricky to calculate since if we decide to use the overflow
- area we basicaly have to start over. So for these we build up a
- list of just the inside margin glyphs and manipulate it to
- determine the needed info. */
- {
- glyph_block_dynarr *ib;
- int avail_in, avail_out;
- int done = 0;
- int marker = 0;
- int used_in, used_out;
-
- elt = 0;
- used_in = used_out = 0;
- ib = Dynarr_new (struct glyph_block);
- while (elt < Dynarr_length (dl->right_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
- {
- gb->width = glyph_width (gb->glyph, gb->findex, 0, window);
- used_in += gb->width;
- Dynarr_add (ib, *gb);
- }
-
- elt++;
- }
-
- if (white_out_cnt)
- avail_in = 0;
- else
- avail_in = dl->bounds.right_in - white_in_end;
-
- if (!use_overflow)
- avail_out = 0;
- else
- avail_out = dl->bounds.right_out - white_out_end;
-
- marker = 0;
- while (!done && marker < Dynarr_length (ib))
- {
- int width = Dynarr_atp (ib, marker)->width;
-
- /* If everything now fits in the available inside margin
- space, we're done. */
- if (used_in <= avail_in)
- done = 1;
- else
- {
- /* Otherwise see if we have room to move a glyph to the
- outside. */
- if (used_out + width <= avail_out)
- {
- used_out += width;
- used_in -= width;
- }
- else
- done = 1;
- }
-
- if (!done)
- marker++;
- }
-
- /* At this point we now know that everything from marker on goes in
- the inside margin and everything before it goes in the outside
- margin. The stuff going into the outside margin is guaranteed
- to fit, but we may have to trim some stuff from the inside. */
-
- in_in_start = dl->bounds.right_in;
- in_out_end = dl->bounds.right_in;
- in_out_cnt = in_in_cnt = 0;
-
- Dynarr_free (ib);
- elt = 0;
- while (elt < Dynarr_length (dl->right_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have been handled in add_glyph_rune */
-
- if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
- {
- int width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (used_out)
- {
- in_out_cnt++;
- in_out_end += width;
- gb->width = width;
- gb->active = 1;
- used_out -= width;
- }
- else if (in_in_start - width >= white_in_end)
- {
- in_in_cnt++;
- in_in_start -= width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
- }
-
- /* Determine how many outside margin glyphs we can display. They
- always start at the right outside margin and can only use the
- outside margin space. */
- out_start = dl->bounds.right_out;
- out_cnt = 0;
- elt = 0;
-
- while (elt < Dynarr_length (dl->right_glyphs))
- {
- struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
-
- if (NILP (gb->extent))
- abort (); /* these should have beeb handled in add_glyph_rune */
-
- if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN)
- {
- int width = glyph_width (gb->glyph, gb->findex, 0, window);
-
- if (out_start - width >= in_out_end)
- {
- out_cnt++;
- out_start -= width;
- gb->width = width;
- gb->active = 1;
- }
- else
- gb->active = 0;
- }
-
- elt++;
- }
-
- /* Now that we now where everything goes, we add the glyphs as runes
- to the appropriate display blocks. */
- if (out_cnt || in_out_cnt || white_out_cnt)
- {
- odb = get_display_block_from_line (dl, RIGHT_OUTSIDE_MARGIN);
- /* #### See comments before odb->start_pos init in
- create_left_glyph_block */
- odb->start_pos = dl->bounds.right_in;
- odb->end_pos = dl->bounds.right_out;
- Dynarr_reset (odb->runes);
- }
- else
- odb = 0;
-
- if (in_in_cnt || white_in_cnt)
- {
- idb = get_display_block_from_line (dl, RIGHT_INSIDE_MARGIN);
- idb->start_pos = dl->bounds.right_white;
- /* #### See comments before odb->start_pos init in
- create_left_glyph_block */
- idb->end_pos = dl->bounds.right_in;
- Dynarr_reset (idb->runes);
- }
- else
- idb = 0;
-
- /* First add the whitespace margin glyphs which are actually in the
- inside margin. */
- if (white_in_cnt)
- {
- end_xpos = add_margin_runes (dl, idb, dl->bounds.right_white,
- white_in_cnt, GL_WHITESPACE, RIGHT_GLYPHS,
- window);
- }
- else
- end_xpos = dl->bounds.right_white;
-
- /* Make sure that the area between the end of the whitespace glyphs
- and the inside margin glyphs is cleared. */
- if (in_in_cnt && (in_in_start - end_xpos))
- {
- add_margin_blank (dl, idb, w, end_xpos, in_in_start - end_xpos,
- RIGHT_GLYPHS);
- }
-
- /* Next add the inside margin glyphs which are actually in the
- inside margin. */
- if (in_in_cnt)
- {
- end_xpos = add_margin_runes (dl, idb, in_in_start, in_in_cnt,
- GL_INSIDE_MARGIN, RIGHT_GLYPHS, window);
- }
-
- /* If we didn't add any inside margin glyphs then make sure the rest
- of the inside margin area gets cleared. */
- if (idb && (dl->bounds.right_in - end_xpos))
- {
- add_margin_blank (dl, idb, w, end_xpos, dl->bounds.right_in - end_xpos,
- RIGHT_GLYPHS);
- }
-
- /* Next add any whitespace glyphs in the outside margin. */
- if (white_out_cnt)
- {
- end_xpos = add_margin_runes (dl, odb, dl->bounds.right_in, white_out_cnt,
- GL_WHITESPACE, RIGHT_GLYPHS, window);
- }
- else
- end_xpos = dl->bounds.right_in;
-
- /* Next add any inside margin glyphs in the outside margin. */
- if (in_out_cnt)
- {
- end_xpos = add_margin_runes (dl, odb, end_xpos, in_out_cnt,
- GL_INSIDE_MARGIN, RIGHT_GLYPHS, window);
- }
-
- /* There may be space between any whitespace or inside margin glyphs
- in the outside margin and the actual outside margin glyphs. */
- if (odb && (out_start - end_xpos))
- {
- add_margin_blank (dl, odb, w, end_xpos, out_start - end_xpos,
- RIGHT_GLYPHS);
- }
-
- /* Finally, add the outside margin glyphs. */
- if (out_cnt)
- {
- add_margin_runes (dl, odb, out_start, out_cnt, GL_OUTSIDE_MARGIN,
- RIGHT_GLYPHS, window);
- }
- }
-
- /*****************************************************************************
- regenerate_window
-
- For a given window and starting position in the buffer it contains,
- ensure that the TYPE display lines accurately represent the
- presentation of the window. We pass the buffer instead of getting it
- from the window since redisplay_window may have temporarily changed
- it to the echo area buffer.
- ****************************************************************************/
- void
- regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
- {
- struct frame *f = XFRAME (w->frame);
- struct buffer *b = XBUFFER (w->buffer);
- int ypos = WINDOW_TEXT_TOP (w);
- int yend = WINDOW_TEXT_BOTTOM (w);
-
- prop_block_dynarr *prop;
- layout_bounds bounds;
- display_line_dynarr *dla;
- struct display_line modeline;
- struct display_line *mlp = 0;
- int need_modeline;
-
- /* The lines had better exist by this point. */
- if (!(dla = window_display_lines (w, type)))
- abort ();
- Dynarr_reset (dla);
- w->max_line_len = 0;
-
- /* Normally these get updated in redisplay_window but it is possible
- for this function to get called from some other points where that
- update may not have occurred. This acts as a safety check. */
- if (!Dynarr_length (w->face_cache_elements))
- reset_face_cache_elements (w);
- if (!Dynarr_length (w->glyph_cache_elements))
- reset_glyph_cache_elements (w);
-
- Fset_marker (w->start[type], make_number (start_pos), w->buffer);
- Fset_marker (w->pointm[type], make_number (point), w->buffer);
- w->last_point_x[type] = -1;
- w->last_point_y[type] = -1;
-
- /* minibuffer windows don't have modelines */
- if (MINI_WINDOW_P (w))
- need_modeline = 0;
- /* windows which haven't had it turned off do */
- else if (WINDOW_HAS_MODELINE_P (w))
- need_modeline = 1;
- /* windows which have it turned off don't have a divider if there is
- a horizontal scrollbar */
- else if (window_scrollbar_height (w))
- need_modeline = 0;
- /* and in this case there is none */
- else
- need_modeline = 1;
-
- /* Add a place marker for the modeline. We wait to generate it
- until after we generate the rest of the window because it depends
- on values generated by doing just that. */
- if (need_modeline)
- {
- if (Dynarr_largest (dla) > 0)
- mlp = Dynarr_atp (dla, 0);
- else
- {
- memset (&modeline, 0, sizeof (struct display_line));
- }
-
- if (mlp)
- Dynarr_add (dla, *mlp);
- else
- Dynarr_add (dla, modeline);
- }
-
- bounds = calculate_display_line_boundaries (w, 0);
-
- if (MINI_WINDOW_P (w)
- && !NILP (Vminibuf_prompt)
- && !echo_area_active (f)
- && start_pos == BUF_BEGV (b))
- {
- struct prop_block pb;
- prop = Dynarr_new (struct prop_block);
-
- pb.type = PROP_MINIBUF_PROMPT;
- pb.data.p_string.str = string_data (XSTRING (Vminibuf_prompt));
- pb.data.p_string.len = string_length (XSTRING (Vminibuf_prompt));
- pb.data.p_string.pos = 0;
- Dynarr_add (prop, pb);
- }
- else
- prop = 0;
-
- while (ypos < yend)
- {
- struct display_line dl;
- struct display_line *dlp;
- int local;
-
- if (Dynarr_length (dla) < Dynarr_largest (dla))
- {
- dlp = Dynarr_atp (dla, Dynarr_length (dla));
- local = 0;
- }
- else
- {
- dlp = &dl;
- memset (dlp, 0, sizeof (struct display_line));
- local = 1;
- }
-
- dlp->bounds = bounds;
- dlp->offset = 0;
- start_pos = generate_display_line (w, dlp, 1, start_pos,
- w->hscroll, &prop, type);
- dlp->ypos = ypos + dlp->ascent;
- ypos = dlp->ypos + dlp->descent;
-
- if (ypos > yend)
- {
- int visible_height = dlp->ascent + dlp->descent;
-
- dlp->clip = (ypos - yend);
- visible_height -= dlp->clip;
-
- if (visible_height < VERTICAL_CLIP (w, 1))
- {
- if (local)
- free_display_line (dlp);
- break;
- }
- }
- else
- dlp->clip = 0;
-
- if (dlp->cursor_elt != -1)
- {
- /* #### This check is steaming crap. Have to get things
- fixed so when create_text_block hits EOB, we're done,
- period. */
- if (w->last_point_x[type] == -1)
- {
- w->last_point_x[type] = dlp->cursor_elt;
- w->last_point_y[type] = Dynarr_length (dla);
- }
- else
- {
- /* #### This means that we've added a cursor at EOB
- twice. Yuck oh yuck. */
- struct display_block *db =
- get_display_block_from_line (dlp, TEXT);
-
- Dynarr_atp (db->runes, dlp->cursor_elt)->cursor_type = NO_CURSOR;
- dlp->cursor_elt = -1;
- }
- }
-
- if (dlp->num_chars > w->max_line_len)
- w->max_line_len = dlp->num_chars;
-
- Dynarr_add (dla, *dlp);
-
- /* #### This isn't right, but it is close enough for now. */
- w->window_end_pos[type] = start_pos;
-
- /* #### This type of check needs to be done down in the
- generate_display_line call. */
- if (start_pos > BUF_ZV (b))
- break;
- }
-
- if (prop)
- Dynarr_free (prop);
-
- /* #### More not quite right, but close enough. */
- /* #### Ben sez: apparently window_end_pos[] is measured
- as the number of characters between the window end and the
- end of the buffer? This seems rather weirdo. What's
- the justification for this? */
- w->window_end_pos[type] = BUF_Z (b) - w->window_end_pos[type];
-
- if (need_modeline)
- {
- /* We know that this is the right thing to use because we put it
- there when we first started working in this function. */
- mlp = Dynarr_atp (dla, 0);
- generate_modeline (w, mlp, type);
- }
- }
-
- /*****************************************************************************
- regenerate_modeline
-
- Update just the modeline. Assumes the desired display structs. If
- they do not have a modeline block, it does nothing.
- ****************************************************************************/
- static void
- regenerate_modeline (struct window *w)
- {
- display_line_dynarr *dla = window_display_lines (w, DESIRED_DISP);
-
- if (!Dynarr_length (dla) || !Dynarr_atp (dla, 0)->modeline)
- return;
- else
- {
- generate_modeline (w, Dynarr_atp (dla, 0), DESIRED_DISP);
- redisplay_update_line (w, 0, 0, 0);
- }
- }
-
- #define REGEN_INC_FIND_START_END \
- do { \
- /* Determine start and end of lines. */ \
- if (!Dynarr_length (cdla)) \
- return 0; \
- else \
- { \
- if (Dynarr_atp (cdla, 0)->modeline && Dynarr_atp (ddla, 0)->modeline) \
- { \
- dla_start = 1; \
- } \
- else if (!Dynarr_atp (cdla, 0)->modeline \
- && !Dynarr_atp (ddla, 0)->modeline) \
- { \
- dla_start = 0; \
- } \
- else \
- abort (); /* structs differ */ \
- \
- dla_end = Dynarr_length (cdla) - 1; \
- } \
- \
- start_pos = (Dynarr_atp (cdla, dla_start)->bufpos \
- + Dynarr_atp (cdla, dla_start)->offset); \
- /* If this isn't true, then startp has changed and we need to do a \
- full regen. */ \
- if (startp != start_pos) \
- return 0; \
- \
- /* Point is outside the visible region so give up. */ \
- if (pointm < start_pos) \
- return 0; \
- \
- } while (0)
-
- /*****************************************************************************
- regenerate_window_extents_only_changed
-
- This attempts to incrementally update the display structures. It
- returns a boolean indicating success or failure. This function is
- very similar to regenerate_window_incrementally and is in fact only
- called from that function. However, because of the nature of the
- changes it deals with it sometimes makes different assumptions which
- can lead to success which are much more difficult to make when dealing
- with buffer changes.
- ****************************************************************************/
- static int
- regenerate_window_extents_only_changed (struct window *w, Bufpos startp,
- Bufpos pointm,
- Charcount beg_unchanged,
- Charcount end_unchanged)
- {
- struct buffer *b = XBUFFER (w->buffer);
- display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
- display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
-
- int dla_start = 0;
- int dla_end, line;
- int first_line, last_line;
- Bufpos start_pos;
- /* Don't define this in the loop where it is used because we
- definitely want its value to survive between passes. */
- prop_block_dynarr *prop = NULL;
-
- /* If we don't have any buffer change recorded but the modiff flag has
- been incremented, then fail. I'm not sure of the exact circumstances
- under which this can happen, but I believe that it is probably a
- reasonable happening. */
- if (!point_visible (w, pointm, CURRENT_DISP)
- || XINT (w->last_modified[CURRENT_DISP]) < BUF_MODIFF (b))
- return 0;
-
- /* If the cursor is moved we attempt to update it. If we succeed we
- go ahead and proceed with the optimization attempt. */
- if (!EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
- || pointm != marker_position (w->last_point[CURRENT_DISP]))
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- struct frame *sel_f = device_selected_frame (d);
- int success = 0;
-
- if (w->last_point_x[CURRENT_DISP] != -1
- && w->last_point_y[CURRENT_DISP] != -1)
- {
-
- if (redisplay_move_cursor (w, pointm, WINDOW_IS_TTY (w)))
- {
- /* Always regenerate the modeline in case it is
- displaying the current line or column. */
- regenerate_modeline (w);
- success = 1;
- }
- }
- else if (w != XWINDOW (FRAME_SELECTED_WINDOW (sel_f)))
- {
- if (f->modeline_changed)
- regenerate_modeline (w);
- success = 1;
- }
-
- if (!success)
- return 0;
- }
-
- if (beg_unchanged == -1 && end_unchanged == -1)
- return 1;
-
- /* assert: There are no buffer modifications or they are all below the
- visible region. We assume that regenerate_window_incrementally has
- not called us unless this is true. */
-
- REGEN_INC_FIND_START_END;
-
- /* If the changed are starts before the visible area, give up. */
- if (beg_unchanged < startp)
- return 0;
-
- /* Find what display line the extent changes first affect. */
- line = dla_start;
- while (line <= dla_end)
- {
- struct display_line *dl = Dynarr_atp (cdla, line);
- Bufpos lstart = dl->bufpos + dl->offset;
- Bufpos lend = dl->end_bufpos + dl->offset;
-
- if (beg_unchanged >= lstart && beg_unchanged <= lend)
- break;
-
- line++;
- }
-
- /* If the changes are below the visible area then if point hasn't
- moved return success otherwise fail in order to be safe. */
- if (line > dla_end)
- {
- if (EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
- && pointm == marker_position (w->last_point[CURRENT_DISP]))
- return 1;
- else
- return 0;
- }
-
- /* At this point we know what line the changes first affect. We now
- begin redrawing lines as long as we are still in the affected
- region and the line's size and positioning don't change.
- Otherwise we fail. If we fail we will have altered the desired
- structs which could lead to an assertion failure. However, if we
- fail the next thing that is going to happen is a full regen so we
- will actually end up being safe. */
- w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
- w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
- Fset_marker (w->last_start[DESIRED_DISP], make_number (startp), w->buffer);
- Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm), w->buffer);
-
- first_line = last_line = line;
- while (line <= dla_end)
- {
- Bufpos old_start, old_end, new_start;
- struct display_line *cdl = Dynarr_atp (cdla, line);
- struct display_line *ddl = Dynarr_atp (ddla, line);
- struct display_block *db;
- int initial_size;
-
- assert (cdl->bufpos == ddl->bufpos);
- assert (cdl->end_bufpos == ddl->end_bufpos);
- assert (cdl->offset == ddl->offset);
-
- db = get_display_block_from_line (ddl, TEXT);
- initial_size = Dynarr_length (db->runes);
- old_start = ddl->bufpos + ddl->offset;
- old_end = ddl->end_bufpos + ddl->offset;
-
- /* If this is the first line being updated and it used
- propogation data, fail. Otherwise we'll be okay because
- we'll have the necessary propogation data. */
- if (line == first_line && ddl->used_prop_data)
- return 0;
-
- new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset,
- w->hscroll, &prop, DESIRED_DISP);
- ddl->offset = 0;
-
- /* #### If there is propogated stuff the fail. We could
- probably actually deal with this if the line had propogated
- information when originally created by a full
- regeneration. */
- if (prop)
- {
- Dynarr_free (prop);
- return 0;
- }
-
- /* If any line position parameters have changed or a
- cursor has disappeared or disappeared, fail. */
- db = get_display_block_from_line (ddl, TEXT);
- if (cdl->ypos != ddl->ypos
- || cdl->ascent != ddl->ascent
- || cdl->descent != ddl->descent
- || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
- || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
- || old_start != ddl->bufpos
- || old_end != ddl->end_bufpos
- || initial_size != Dynarr_length (db->runes))
- {
- return 0;
- }
-
- if (ddl->cursor_elt != -1)
- {
- w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
- w->last_point_y[DESIRED_DISP] = line;
- }
-
- last_line = line;
-
- /* If the extent changes end on the line we just updated then
- we're done. Otherwise go on to the next line. */
- if (end_unchanged <= ddl->end_bufpos)
- break;
- else
- line++;
- }
-
- redisplay_update_line (w, first_line, last_line, 1);
- return 1;
- }
-
- /*****************************************************************************
- regenerate_window_incrementally
-
- Attempt to update the display data structures based on knowledge of
- the changed region in the buffer. Returns a boolean indicating
- success or failure. If this function returns a failure then a
- regenerate_window _must_ be performed next in order to maintain
- invariants located here.
- ****************************************************************************/
- static int
- regenerate_window_incrementally (struct window *w, Bufpos startp,
- Bufpos pointm)
- {
- struct buffer *b = XBUFFER (w->buffer);
- display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
- display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
- Charcount beg_unchanged, end_unchanged;
- Charcount extent_beg_unchanged, extent_end_unchanged;
-
- int dla_start = 0;
- int dla_end, line;
- Bufpos start_pos;
-
- /* If this function is called, the current and desired structures
- had better be identical. If they are not, then that is a bug. */
- assert (Dynarr_length (cdla) == Dynarr_length (ddla));
-
- /* We don't handle minibuffer windows yet. The minibuffer prompt
- screws us up. */
- if (MINI_WINDOW_P (w))
- return 0;
-
- extent_beg_unchanged = BUF_EXTENT_BEGIN_UNCHANGED (b);
- extent_end_unchanged = (BUF_EXTENT_END_UNCHANGED (b) == -1
- ? -1
- : BUF_Z (b) - BUF_EXTENT_END_UNCHANGED (b));
-
- /* If nothing has changed in the buffer, then make sure point is ok
- and succeed. */
- if (BUF_BEGIN_UNCHANGED (b) == -1 && BUF_END_UNCHANGED (b) == -1)
- return regenerate_window_extents_only_changed (w, startp, pointm,
- extent_beg_unchanged,
- extent_end_unchanged);
-
- /* We can't deal with deleted newlines. */
- if (BUF_NEWLINE_WAS_DELETED (b))
- return 0;
-
- beg_unchanged = BUF_BEGIN_UNCHANGED (b);
- end_unchanged = (BUF_END_UNCHANGED (b) == -1
- ? -1
- : BUF_Z (b) - BUF_END_UNCHANGED (b));
-
- REGEN_INC_FIND_START_END;
-
- /* If the changed area starts before the visible area, give up. */
- if (beg_unchanged < startp)
- return 0;
-
- /* Find what display line the buffer changes first affect. */
- line = dla_start;
- while (line <= dla_end)
- {
- struct display_line *dl = Dynarr_atp (cdla, line);
- Bufpos lstart = dl->bufpos + dl->offset;
- Bufpos lend = dl->end_bufpos + dl->offset;
-
- if (beg_unchanged >= lstart && beg_unchanged <= lend)
- break;
-
- line++;
- }
-
- /* If the changes are below the visible area then if point hasn't
- moved return success otherwise fail in order to be safe. */
- if (line > dla_end)
- {
- return regenerate_window_extents_only_changed (w, startp, pointm,
- extent_beg_unchanged,
- extent_end_unchanged);
- }
- else
- /* At this point we know what line the changes first affect. We
- now redraw that line. If the changes are contained within it
- we are going to succeed and can update just that one line.
- Otherwise we fail. If we fail we will have altered the desired
- structs which could lead to an assertion failure. However, if
- we fail the next thing that is going to happen is a full regen
- so we will actually end up being safe. */
- {
- Bufpos new_start;
- prop_block_dynarr *prop = NULL;
- struct display_line *cdl = Dynarr_atp (cdla, line);
- struct display_line *ddl = Dynarr_atp (ddla, line);
-
- assert (cdl->bufpos == ddl->bufpos);
- assert (cdl->end_bufpos == ddl->end_bufpos);
- assert (cdl->offset == ddl->offset);
-
- /* If the last rune is already a continuation glyph, fail.
- #### We should be able to handle this better. */
- {
- struct display_block *db = get_display_block_from_line (ddl, TEXT);
- if (Dynarr_length (db->runes))
- {
- struct rune *rb =
- Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-
- if (rb->type == DGLYPH
- && EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
- return 0;
- }
- }
-
- /* If the line was generated using propogation data, fail. */
- if (ddl->used_prop_data)
- return 0;
-
- new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset,
- w->hscroll, &prop, DESIRED_DISP);
- ddl->offset = 0;
-
- /* If there is propagated stuff then it is pretty much a
- guarantee that more than just the one line is affected. */
- if (prop)
- {
- Dynarr_free (prop);
- return 0;
- }
-
- /* If the last rune is now a continuation glyph, fail. */
- {
- struct display_block *db = get_display_block_from_line (ddl, TEXT);
- if (Dynarr_length (db->runes))
- {
- struct rune *rb =
- Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-
- if (rb->type == DGLYPH
- && EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
- return 0;
- }
- }
-
- /* If any line position parameters have changed or a
- cursor has disappeared or disappeared, fail. */
- if (cdl->ypos != ddl->ypos
- || cdl->ascent != ddl->ascent
- || cdl->descent != ddl->descent
- || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
- || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1))
- {
- return 0;
- }
-
- /* If the changed area also ends on this line, then we may be in
- business. Update everything and return success. */
- if (end_unchanged >= ddl->bufpos && end_unchanged <= ddl->end_bufpos)
- {
- w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
- w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
- Fset_marker (w->last_start[DESIRED_DISP], make_number (startp),
- w->buffer);
- Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm),
- w->buffer);
-
- if (ddl->cursor_elt != -1)
- {
- w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
- w->last_point_y[DESIRED_DISP] = line;
- }
-
- redisplay_update_line (w, line, line, 1);
- regenerate_modeline (w);
-
- /* #### For now we just flush the cache until this has been
- tested. After that is done, this should correct the
- cache directly. */
- Dynarr_reset (w->line_start_cache);
-
- /* Adjust the extent changed boundaries to remove any
- overlap with the buffer changes since we've just
- successfully updated that area. */
- if (extent_beg_unchanged != -1
- && extent_beg_unchanged >= beg_unchanged
- && extent_beg_unchanged < end_unchanged)
- extent_beg_unchanged = end_unchanged;
-
- if (extent_end_unchanged != -1
- && extent_end_unchanged >= beg_unchanged
- && extent_end_unchanged < end_unchanged)
- extent_end_unchanged = beg_unchanged - 1;
-
- if (extent_end_unchanged <= extent_beg_unchanged)
- extent_beg_unchanged = extent_end_unchanged = -1;
-
- /* This could lead to odd results if it fails, but since the
- buffer changes update succeeded this probably will to.
- We already know that the extent changes start at or after
- the line because we checked before entering the loop. */
- if (extent_beg_unchanged != -1
- && extent_end_unchanged != -1
- && ((extent_beg_unchanged < ddl->bufpos)
- || (extent_end_unchanged > ddl->end_bufpos)))
- {
- return
- regenerate_window_extents_only_changed (w, startp, pointm,
- extent_beg_unchanged,
- extent_end_unchanged);
- }
- else
- return 1;
- }
- }
-
- /* Oh, well. */
- return 0;
- }
-
- /*****************************************************************************
- regenerate_window_point_center
-
- Given a window and a point, update the given display lines such that
- point is displayed in the middle of the window.
- ****************************************************************************/
- static void
- regenerate_window_point_center (struct window *w, Bufpos point, int type)
- {
- Bufpos startp;
-
- startp = start_with_line_at_pixpos (w, point, window_half_pixpos (w));
- regenerate_window (w, startp, point, type);
- Fset_marker (w->start[type], make_number (startp), w->buffer);
-
- return;
- }
-
- /*****************************************************************************
- point_visible
-
- Given a window and a set of display lines, return a boolean indicating
- whether the given point is contained within.
- ****************************************************************************/
- static int
- point_visible (struct window *w, Bufpos point, int type)
- {
- struct buffer *b = XBUFFER (w->buffer);
- display_line_dynarr *dla = window_display_lines (w, type);
- int first_line;
-
- if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
- first_line = 1;
- else
- first_line = 0;
-
- if (Dynarr_length (dla) > first_line)
- {
- Bufpos start, end;
- struct display_line *dl = Dynarr_atp (dla, first_line);
-
- start = dl->bufpos;
- end = BUF_Z (b) - w->window_end_pos[type] - 1;
-
- if (point >= start && point <= end)
- {
- if (!MINI_WINDOW_P (w) && scroll_on_clipped_lines)
- {
- dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
-
- if (point >= (dl->bufpos + dl->offset)
- && point <= (dl->end_bufpos + dl->offset))
- return (!dl->clip);
- else
- return 1;
- }
- else
- return 1;
- }
- else
- return 0;
- }
- else
- return 0;
- }
-
- /*****************************************************************************
- window_half_pixpos
-
- Return pixel position the middle of the window, not including the
- modeline and any potential horizontal scrollbar.
- ****************************************************************************/
- int
- window_half_pixpos (struct window *w)
- {
- return (WINDOW_TEXT_TOP (w) + (WINDOW_TEXT_HEIGHT (w) >> 1));
- }
-
- /*****************************************************************************
- line_at_center
-
- Return the display line which is currently in the middle of the
- window W for display lines TYPE.
- ****************************************************************************/
- int
- line_at_center (struct window *w, int type)
- {
- display_line_dynarr *dla = window_display_lines (w, type);
- int half = window_half_pixpos (w);
- int elt;
- int first_elt = (MINI_WINDOW_P (w) ? 0 : 1);
-
- for (elt = first_elt; elt < Dynarr_length (dla); elt++)
- {
- struct display_line *dl = Dynarr_atp (dla, elt);
- int line_bot = dl->ypos + dl->descent;
-
- if (line_bot > half)
- return elt;
- }
-
- /* We may not have a line at the middle if the end of the buffer is
- being displayed. */
- return -1;
- }
-
- /*****************************************************************************
- point_at_center
-
- Return a value for point that would place it at the beginning of the
- line which is in the middle of the window.
- ****************************************************************************/
- Bufpos
- point_at_center (struct window *w, int type, int regen, Bufpos start,
- Bufpos point)
- {
- int line;
-
- if (regen)
- regenerate_window (w, start, point, type);
- line = line_at_center (w, type);
-
- if (line == -1)
- return BUF_ZV (XBUFFER (w->buffer));
- else
- {
- display_line_dynarr *dla = window_display_lines (w, type);
- struct display_line *dl = Dynarr_atp (dla, line);
-
- return dl->bufpos;
- }
- }
-
- /*****************************************************************************
- redisplay_window
-
- For a given window, ensure that the current visual representation is
- accurate.
- ****************************************************************************/
- static void
- redisplay_window (Lisp_Object window, int skip_selected)
- {
- struct window *w = XWINDOW (window);
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- Lisp_Object old_buffer = w->buffer;
- struct buffer *b;
- int echo_active = 0;
- int startp = 1;
- int pointm;
- int selected;
- int skip_output = 0;
- int truncation_changed;
- int inactive_minibuffer =
- (MINI_WINDOW_P (w) && f != device_selected_frame (d));
-
- /* #### In the new world this function actually does a bunch of
- optimizations such as buffer-based scrolling, but none of that is
- implemented yet. */
-
- /* If this is a combination window, do its children; that's all.
- The selected window is always a leaf so we don't check for
- skip_selected here. */
- if (!NILP (w->vchild))
- {
- redisplay_windows (w->vchild, skip_selected);
- return;
- }
- if (!NILP (w->hchild))
- {
- redisplay_windows (w->hchild, skip_selected);
- return;
- }
-
- /* Is this window the selected window on its frame? */
- selected =
- (w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))));
- if (skip_selected && selected)
- return;
-
- /* It is possible that the window is not fully initialized yet. */
- if (NILP (w->buffer))
- return;
-
- if (MINI_WINDOW_P (w) && echo_area_active (f))
- {
- w->buffer = Vecho_area_buffer;
- echo_active = 1;
- }
-
- b = XBUFFER (w->buffer);
-
- if (echo_active)
- pointm = 1;
- else
- {
- if (selected)
- {
- pointm = BUF_PT (b);
- }
- else
- {
- pointm = marker_position (w->pointm[CURRENT_DISP]);
-
- if (pointm < BUF_BEGV (b))
- pointm = BUF_BEGV (b);
- else if (pointm > BUF_ZV (b))
- pointm = BUF_ZV (b);
- }
- }
- Fset_marker (w->pointm[DESIRED_DISP], make_number (pointm), old_buffer);
-
- /* If the buffer has changed we have to invalid all of our face
- cache elements. */
- if ((!echo_active && b != window_display_buffer (w))
- || !Dynarr_length (w->face_cache_elements)
- || f->faces_changed)
- reset_face_cache_elements (w);
- else
- mark_face_cache_elements_as_not_updated (w);
-
- /* Ditto the glyph cache elements. */
- if ((!echo_active && b != window_display_buffer (w))
- || !Dynarr_length (w->glyph_cache_elements))
- reset_glyph_cache_elements (w);
- else
- mark_glyph_cache_elements_as_not_updated (w);
-
- /* If the marker's buffer is not the window's buffer, then we need
- to find a new starting position. */
- if (!MINI_WINDOW_P (w)
- && !EQ (Fmarker_buffer (w->start[CURRENT_DISP]), w->buffer))
- {
- regenerate_window_point_center (w, pointm, DESIRED_DISP);
-
- goto regeneration_done;
- }
-
- if (echo_active)
- startp = 1;
- else
- {
- startp = marker_position (w->start[CURRENT_DISP]);
- if (startp < BUF_BEGV (b))
- startp = BUF_BEGV (b);
- else if (startp > BUF_ZV (b))
- startp = BUF_ZV (b);
- }
- Fset_marker (w->start[DESIRED_DISP], make_number (startp), old_buffer);
-
- truncation_changed = (find_window_mirror (w)->truncate_win !=
- window_truncation_on (w));
-
- /* If w->force_start is set, then some function set w->start and we
- should display from there and change point, if necessary, to
- ensure that it is visible. */
- if (w->force_start || inactive_minibuffer)
- {
- w->force_start = 0;
- w->last_modified[DESIRED_DISP] = Qzero;
- w->last_facechange[DESIRED_DISP] = Qzero;
-
- regenerate_window (w, startp, pointm, DESIRED_DISP);
-
- if (!point_visible (w, pointm, DESIRED_DISP) && !inactive_minibuffer)
- {
- pointm = point_at_center (w, DESIRED_DISP, 0, 0, 0);
-
- if (selected)
- BUF_SET_PT (b, pointm);
-
- Fset_marker (w->pointm[DESIRED_DISP], make_number (pointm),
- old_buffer);
-
- /* #### BUFU amounts of overkil just to get the cursor
- location marked properly. FIX ME FIX ME FIX ME */
- regenerate_window (w, startp, pointm, DESIRED_DISP);
- }
-
- goto regeneration_done;
- }
-
- /* If nothing has changed since the last redisplay, then we just
- need to make sure that point is still visible. */
- if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
- && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b)
- && pointm >= startp
- /* This check is to make sure we restore the minibuffer after a
- temporary change to the echo area. */
- && !(MINI_WINDOW_P (w) && f->buffers_changed)
- && !f->frame_changed
- && !truncation_changed)
- {
- /* Check if the cursor has actually moved. */
- if (EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
- && pointm == marker_position (w->last_point[CURRENT_DISP])
- && selected
- && !w->windows_changed
- && !f->clip_changed
- && !f->extents_changed
- && !f->faces_changed
- && !f->point_changed
- && !f->windows_structure_changed)
- {
- /* If not, we're done. */
- if (f->modeline_changed)
- regenerate_modeline (w);
-
- skip_output = 1;
- goto regeneration_done;
- }
- else
- {
- /* If the new point is visible in the redisplay structures,
- then let the output update routines handle it, otherwise
- do things the hard way. */
- if (!w->windows_changed
- && !f->clip_changed
- && !f->extents_changed
- && !f->faces_changed
- && !f->windows_structure_changed)
- {
- if (point_visible (w, pointm, CURRENT_DISP)
- && w->last_point_x[CURRENT_DISP] != -1
- && w->last_point_y[CURRENT_DISP] != -1)
- {
- if (redisplay_move_cursor (w, pointm, FRAME_IS_TTY (f)))
- {
- /* Always regenerate in case it is displaying
- the current line or column. */
- regenerate_modeline (w);
-
- skip_output = 1;
- goto regeneration_done;
- }
- }
- else if (!selected && !f->point_changed)
- {
- if (f->modeline_changed)
- regenerate_modeline (w);
-
- skip_output = 1;
- goto regeneration_done;
- }
- }
-
- /* If we weren't able to take the shortcut method, then use
- the brute force method. */
- regenerate_window (w, startp, pointm, DESIRED_DISP);
-
- if (point_visible (w, pointm, DESIRED_DISP))
- goto regeneration_done;
- }
- }
-
- /* Check if the starting point is no longer at the beginning of a
- line, in which case find a new starting point. We also recenter
- if our start position is equal to point-max. Otherwise we'll end
- up with a blank window. */
- else if (((w->start_at_line_beg || MINI_WINDOW_P (w))
- && !(startp == BUF_BEGV (b)
- || BUF_FETCH_CHAR (b, startp - 1) == '\n'))
- || (pointm == startp &&
- EQ (Fmarker_buffer (w->last_start[CURRENT_DISP]), w->buffer) &&
- startp < marker_position (w->last_start[CURRENT_DISP]))
- || (startp == BUF_ZV (b)))
- {
- regenerate_window_point_center (w, pointm, DESIRED_DISP);
-
- goto regeneration_done;
- }
- /* See if we can update the data structures locally based on
- knowledge of what changed in the buffer. */
- else if (!w->windows_changed
- && !f->clip_changed
- && !f->faces_changed
- && !f->windows_structure_changed
- && !f->frame_changed
- && !truncation_changed
- && pointm >= startp
- && regenerate_window_incrementally (w, startp, pointm))
- {
- if (f->modeline_changed
- || XINT (w->last_modified[CURRENT_DISP]) < BUF_MODIFF (b)
- || XINT (w->last_facechange[CURRENT_DISP]) < BUF_FACECHANGE (b))
- regenerate_modeline (w);
-
- skip_output = 1;
- goto regeneration_done;
- }
- /* #### This is where a check for structure based scrolling would go. */
- /* If all else fails, try just regenerating and see what happens. */
- else
- {
- regenerate_window (w, startp, pointm, DESIRED_DISP);
-
- if (point_visible (w, pointm, DESIRED_DISP))
- goto regeneration_done;
- }
-
- /* We still haven't gotten the window regenerated with point
- visible. Next we try scrolling a little and see if point comes
- back onto the screen. */
- if (scroll_step)
- {
- Bufpos bufpos;
-
- bufpos = vmotion (w, startp,
- (pointm < startp) ? -scroll_step : scroll_step, 0);
- regenerate_window (w, bufpos, pointm, DESIRED_DISP);
-
- if (point_visible (w, pointm, DESIRED_DISP))
- goto regeneration_done;
- }
-
- /* We still haven't managed to get the screen drawn with point on
- the screen, so just center it and be done with it. */
- regenerate_window_point_center (w, pointm, DESIRED_DISP);
-
-
- regeneration_done:
-
- /* If the window's frame is changed then reset the current display
- lines in order to force a full repaint. */
- if (f->frame_changed)
- {
- display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
-
- Dynarr_reset (cla);
- }
-
- /* Must do this before calling redisplay_output_window because it
- sets some markers on the window. */
- if (MINI_WINDOW_P (w) && echo_area_active (f))
- w->buffer = old_buffer;
-
- /* These also have to be set before calling redisplay_output_window
- since it sets the CURRENT_DISP values based on them. */
- w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
- w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
- Fset_marker (w->last_start[DESIRED_DISP], make_number (startp), w->buffer);
- Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm), w->buffer);
-
- if (!skip_output)
- {
- Bufpos start = marker_position (w->start[DESIRED_DISP]);
- Bufpos end = (w->window_end_pos[DESIRED_DISP] == -1
- ? BUF_ZV (b)
- : BUF_Z (b) - w->window_end_pos[DESIRED_DISP] - 1);
-
- update_line_start_cache (w, start, end, pointm, 1);
- redisplay_output_window (w);
- }
-
- /* #### This should be dependent on face changes and will need to be
- somewhere else once tty updates occur on a per-frame basis. */
- mark_face_cache_elements_as_clean (w);
-
- w->windows_changed = 0;
- }
-
- /*****************************************************************************
- reset_buffer_changes
- reset_buffer_changes_mapfun -- internal
-
- Call buffer_reset_changes for all buffers present in any window
- currently visible in all frames on all devices.
- #### There has to be a better way to do this.
- ****************************************************************************/
-
- static int
- reset_buffer_changes_mapfun (struct window *w, void *ignored_closure)
- {
- buffer_reset_changes (XBUFFER (w->buffer));
- return 0;
- }
-
- static void
- reset_buffer_changes (void)
- {
- Lisp_Object dev, frm;
- DEVICE_AND_FRAME_LOOP (dev, frm)
- {
- struct frame *f = XFRAME (XCAR (frm));
-
- if (FRAME_VISIBLE_P (f))
- map_windows (f, reset_buffer_changes_mapfun, 0);
- }
- }
-
- /*****************************************************************************
- redisplay_windows
-
- Ensure that all windows underneath the given window in the window
- hierarchy are correctly displayed.
- ****************************************************************************/
- static void
- redisplay_windows (Lisp_Object window, int skip_selected)
- {
- for (; !NILP (window) ; window = XWINDOW (window)->next)
- {
- redisplay_window (window, skip_selected);
- }
- }
-
- /*****************************************************************************
- redisplay_frame
-
- Ensure that all windows on the given frame are correctly displayed.
- ****************************************************************************/
- static int
- redisplay_frame (struct frame *f)
- {
- struct device *d = XDEVICE (f->device);
- #if 0 /* The preemption check itself takes a lot of time,
- so don't do it here */
- int preempted;
-
- REDISPLAY_PREEMPTION_CHECK;
- if (preempted)
- return 1;
- #endif
-
- /* Before we put a hold on frame size changes, attempt to process
- any which are already pending. */
- if (f->size_change_pending)
- change_frame_size (f, f->new_height, f->new_width, 1, 0);
-
- /* The menubar and toolbar updates must be done before
- hold_frame_size_changes is called and we are officially
- 'in_display'. They may eval lisp code which may call Fsignal.
- If in_display is set Fsignal will abort. */
-
- /* Update the menubar. It is done first since it could change
- the menubar's visibility. This way we avoid having flashing
- caused by an Expose event generated by the visibility change
- being handled. */
- update_frame_menubars (f);
-
- /* Update the toolbars. */
- update_frame_toolbars (f);
-
- /* We do not allow changes in the frame size to be processed
- while redisplay is working. */
- /* #### If a change does occur we should probably actually be
- preempting redisplay. */
- hold_frame_size_changes ();
-
- /* If we clear the frame we have to force its contents to be redrawn. */
- if (f->clear)
- f->frame_changed = 1;
-
- /* Erase the frame before outputing its contents. */
- if (f->clear)
- DEVMETH (d, clear_frame, (f));
-
- /* Do the selected window first. */
- redisplay_window (FRAME_SELECTED_WINDOW (f), 0);
-
- /* Then do the rest. */
- redisplay_windows (f->root_window, 1);
-
- /* We now call the output_end routine for tty frames. We delay
- doing so in order to avoid cursor flicker. So much for 100%
- encapsulation. */
- if (FRAME_IS_TTY (f))
- DEVMETH (d, output_end, (d));
-
- /* #### We should make this conditional. */
- update_frame_title (f);
-
- f->buffers_changed = 0;
- f->clip_changed = 0;
- f->extents_changed = 0;
- f->faces_changed = 0;
- f->frame_changed = 0;
- f->menubar_changed = 0;
- f->modeline_changed = 0;
- f->point_changed = 0;
- f->toolbar_changed = 0;
- f->windows_changed = 0;
- f->windows_structure_changed = 0;
- f->window_face_cache_reset = 0;
-
- f->clear = 0;
-
- if (!f->size_change_pending)
- f->size_changed = 0;
-
- /* Allow frame size changes to occur again. */
- unhold_frame_size_changes (f);
-
- return 0;
- }
-
- /*****************************************************************************
- redisplay_device
-
- Ensure that all frames on the given device are correctly displayed.
- ****************************************************************************/
- static int
- redisplay_device (struct device *d)
- {
- Lisp_Object frm;
- int preempted = 0;
- int size_change_failed = 0;
-
- if (DEVICE_IS_STREAM (d)) /* nothing to do */
- return 0;
-
- /* It is possible that redisplay has been called before the
- device is fully initialized. If so then continue with the
- next device. */
- if (NILP (DEVICE_SELECTED_FRAME (d)))
- return 0;
-
- REDISPLAY_PREEMPTION_CHECK;
- if (preempted)
- return 1;
-
- /* Always do the selected frame first. */
- frm = DEVICE_SELECTED_FRAME (d);
- if (FRAME_VISIBLE_P (XFRAME (frm)))
- {
- struct frame *f = XFRAME (frm);
-
- if (f->buffers_changed || f->clip_changed || f->extents_changed
- || f->faces_changed || f->frame_changed || f->menubar_changed
- || f->modeline_changed || f->point_changed || f->size_changed
- || f->toolbar_changed || f->windows_changed
- || f->windows_structure_changed)
- {
- preempted = redisplay_frame (f);
- }
-
- if (preempted)
- return 1;
-
- /* If the frame redisplay did not get preempted, then this flag
- should have gotten set to 0. It might be possible for that
- not to happen if a size change event were to occur at an odd
- time. To make sure we don't miss anything we simply don't
- reset the top level flags until the condition ends up being
- in the right state. */
- if (f->size_changed)
- size_change_failed = 1;
- }
-
- FRAME_LOOP (frm, d)
- {
- struct frame *f = XFRAME (XCAR (frm));
-
- if (FRAME_VISIBLE_P (f) && f != XFRAME (DEVICE_SELECTED_FRAME (d)))
- {
- if (f->buffers_changed || f->clip_changed || f->extents_changed
- || f->faces_changed || f->frame_changed || f->menubar_changed
- || f->modeline_changed || f->point_changed || f->size_changed
- || f->toolbar_changed || f->windows_changed ||
- f->windows_structure_changed)
- {
- preempted = redisplay_frame (f);
- }
-
- if (preempted)
- return 1;
-
- if (f->size_change_pending)
- size_change_failed = 1;
- }
- }
-
- /* If we get here then we redisplayed all of our frames without
- getting preempted so mark ourselves as clean. */
- d->buffers_changed = 0;
- d->clip_changed = 0;
- d->extents_changed = 0;
- d->faces_changed = 0;
- d->frame_changed = 0;
- d->menubar_changed = 0;
- d->modeline_changed = 0;
- d->point_changed = 0;
- d->toolbar_changed = 0;
- d->windows_changed = 0;
- d->windows_structure_changed = 0;
-
- if (!size_change_failed)
- d->size_changed = 0;
-
- return 0;
- }
-
- /*****************************************************************************
- redisplay
-
- Ensure that all windows on all frames on all devices are displaying
- the current contents of their respective buffers.
- ****************************************************************************/
- static void
- redisplay_without_hooks (void)
- {
- Lisp_Object dev;
- int size_change_failed = 0;
-
- if (asynch_device_change_pending)
- handle_asynch_device_change ();
-
- if (!buffers_changed && !clip_changed && !extents_changed && !faces_changed
- && !frame_changed && !menubar_changed && !modeline_changed
- && !point_changed && !size_changed && !toolbar_changed
- && !windows_changed && !windows_structure_changed && !disable_preemption
- && preemption_count < max_preempts)
- return;
-
- DEVICE_LOOP (dev)
- {
- struct device *d = XDEVICE (XCAR (dev));
- int preempted;
-
- if (d->buffers_changed || d->clip_changed || d->extents_changed
- || d->faces_changed || d->frame_changed || d->menubar_changed
- || d->modeline_changed || d->point_changed || d->size_changed
- || d->toolbar_changed || d->windows_changed
- || d->windows_structure_changed)
- {
- preempted = redisplay_device (d);
-
- if (preempted)
- {
- preemption_count++;
- RESET_CHANGED_SET_FLAGS;
- return;
- }
-
- /* See comment in redisplay_device. */
- if (d->size_changed)
- size_change_failed = 1;
- }
- }
- preemption_count = 0;
-
- /* Mark redisplay as accurate */
- buffers_changed = 0;
- clip_changed = 0;
- extents_changed = 0;
- frame_changed = 0;
- menubar_changed = 0;
- modeline_changed = 0;
- point_changed = 0;
- toolbar_changed = 0;
- windows_changed = 0;
- windows_structure_changed = 0;
- RESET_CHANGED_SET_FLAGS;
-
- if (faces_changed)
- {
- mark_all_faces_as_clean ();
- faces_changed = 0;
- }
-
- if (!size_change_failed)
- size_changed = 0;
-
- reset_buffer_changes ();
- }
-
- void
- redisplay (void)
- {
- if (last_display_warning_tick != display_warning_tick &&
- !inhibit_warning_display)
- {
- /* If an error occurs during this function, oh well.
- If we report another warning, we could get stuck in an
- infinite loop reporting warnings. */
- call0_trapping_errors (0, Qdisplay_warning_buffer);
- last_display_warning_tick = display_warning_tick;
- }
- /* The run_hook_trapping_errors functions are smart enough not
- to do any evalling if the hook function is empty, so there
- should not be any significant time loss. All places in the
- C code that call redisplay() are prepared to handle GCing,
- so we should be OK. */
- #if 0
- run_hook_trapping_errors ("Error in pre-redisplay-hook",
- Qpre_redisplay_hook);
- #endif
-
- redisplay_without_hooks ();
-
- #if 0
- run_hook_trapping_errors ("Error in post-redisplay-hook",
- Qpost_redisplay_hook);
- #endif
- }
-
- /*****************************************************************************
- redisplay_echo_area
-
- Ensure that all minibuffers are correctly showing the echo area.
- ****************************************************************************/
-
- DEFUN ("redisplay-echo-area", Fredisplay_echo_area, Sredisplay_echo_area,
- 0, 0, 0,
- "Ensure that all minibuffers are correctly showing the echo area.")
- ()
- {
- Lisp_Object dev;
-
- DEVICE_LOOP (dev)
- {
- struct device *d = XDEVICE (XCAR (dev));
- Lisp_Object frm;
-
- FRAME_LOOP (frm, d)
- {
- struct frame *f = XFRAME (XCAR (frm));
-
- if (FRAME_VISIBLE_P (f))
- {
- redisplay_window (FRAME_MINIBUF_WINDOW (f), 0);
- }
- }
-
- /* We now call the output_end routine for tty frames. We delay
- doing so in order to avoid cursor flicker. So much for 100%
- encapsulation. */
- if (DEVICE_IS_TTY (d))
- DEVMETH (d, output_end, (d));
- }
-
- return Qnil;
- }
-
- /*****************************************************************************
- window_line_number
-
- Inefficiently determine the line number of the line point is on and
- return it as a string. Always do this regardless of whether
- line_number_mode is true.
- ****************************************************************************/
- static char window_line_number_buf[100];
- static char *
- window_line_number (struct window *w, int type)
- {
- struct device *d = XDEVICE (XFRAME (w->frame)->device);
- struct buffer *b = XBUFFER (w->buffer);
- Bufpos end =
- ((w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
- ? BUF_PT (b)
- : marker_position (w->pointm[type]));
- int lots = 999999999;
- int shortage, line;
-
- scan_buffer (b, '\n', end, 0, -lots, &shortage, 0);
- line = lots - shortage + 1;
-
- sprintf (window_line_number_buf, "%d", line);
-
- return (window_line_number_buf);
- }
-
- /*****************************************************************************
- decode_mode_spec
-
- Given a character representing an object in a modeline specification,
- return a string (stored into the global array `mode_spec') with the
- information that object represents.
-
- This function is largely unchanged from previous versions of the
- redisplay engine.
- ****************************************************************************/
- static void
- decode_mode_spec (struct window *w, Emchar spec, int type)
- {
- Lisp_Object obj = Qnil;
- char *str = NULL;
- struct buffer *b = XBUFFER (w->buffer);
-
- Dynarr_reset (mode_spec);
-
- switch (spec)
- {
- /* print buffer name */
- case 'b':
- obj = b->name;
- break;
-
- /* print visited file name */
- case 'f':
- obj = b->filename;
- break;
-
- /* print the current column */
- case 'c':
- {
- int col = current_column (b);
- int temp = col;
- int size = 2;
- char *buf;
-
- while (temp >= 10)
- {
- temp /= 10;
- size++;
- }
-
- buf = (char *) alloca (size * sizeof (char));
- sprintf (buf, "%d", col);
-
- Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
-
- goto decode_mode_spec_done;
- }
- break;
-
- /* print the current line number */
- case 'l':
- str = window_line_number (w, type);
- break;
-
- /* print value of mode-name (obsolete) */
- case 'm':
- obj = b->mode_name;
- break;
-
- /* print Narrow if appropriate */
- case 'n':
- if (BUF_BEGV (b) > BUF_BEG (b)
- || BUF_ZV (b) < BUF_Z (b))
- str = " Narrow";
- break;
-
- /* print %, * or hyphen, if buffer is read-only, modified or neither */
- case '*':
- str = (!NILP (b->read_only)
- ? "%"
- : ((BUF_MODIFF (b) > b->save_modified)
- ? "*"
- : "-"));
- break;
-
- /* print * or hyphen -- XEmacs change to allow a buffer to be
- read-only but still indicate whether it is modified. */
- case '+':
- str = ((BUF_MODIFF (b) > b->save_modified)
- ? "*"
- : (!NILP (b->read_only)
- ? "%"
- : "-"));
- break;
-
- /* #### defined in 19.29 decode_mode_spec, but not in
- modeline-format doc string. */
- /* This differs from %* in that it ignores read-only-ness. */
- case '&':
- str = ((BUF_MODIFF (b) > b->save_modified)
- ? "*"
- : "-");
- break;
-
- /* print process status */
- case 's':
- obj = Fget_buffer_process (w->buffer);
- if (NILP (obj))
- str = GETTEXT ("no process");
- else
- obj = Fsymbol_name (Fprocess_status (obj));
- break;
-
- /* print name of selected frame (only meaningful under X Windows) */
- case 'S':
- obj = XFRAME (w->frame)->name;
- break;
-
- /* indicate TEXT or BINARY */
- case 't':
- #ifdef MSDOS
- str = NILP (b->buffer_file_type) ? "T" : "B";
- #else /* not MSDOS */
- str = "T";
- #endif /* not MSDOS */
-
- /* print percent of buffer above top of window, or Top, Bot or All */
- case 'p':
- {
- Bufpos pos = marker_position (w->start[type]);
- Charcount total = BUF_ZV (b) - BUF_BEGV (b);
-
- /* This had better be while the desired lines are being done. */
- if (w->window_end_pos[type] <= BUF_Z (b) - BUF_ZV (b))
- {
- if (pos <= BUF_BEGV (b))
- str = "All";
- else
- str = "Bottom";
- }
- else if (pos <= BUF_BEGV (b))
- str = "Top";
- else
- {
- /* This hard limit is ok since the string it will hold has a
- fixed maximum length of 3. But just to be safe... */
- char buf[10];
-
- total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
-
- /* We can't normally display a 3-digit number, so get us a
- 2-digit number that is close. */
- if (total == 100)
- total = 99;
-
- sprintf (buf, "%2d%%", total);
- Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
-
- goto decode_mode_spec_done;
- }
- break;
- }
-
- /* print percent of buffer above bottom of window, perhaps plus
- Top, or print Bottom or All */
- case 'P':
- {
- Bufpos toppos = marker_position (w->start[type]);
- Bufpos botpos = BUF_Z (b) - w->window_end_pos[type];
- Charcount total = BUF_ZV (b) - BUF_BEGV (b);
-
- if (botpos >= BUF_ZV (b))
- {
- if (toppos <= BUF_BEGV (b))
- str = "All";
- else
- str = "Bottom";
- }
- else
- {
- /* This hard limit is ok since the string it will hold has a
- fixed maximum length of around 6. But just to be safe... */
- char buf[10];
-
- total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
-
- /* We can't normally display a 3-digit number, so get us a
- 2-digit number that is close. */
- if (total == 100)
- total = 99;
-
- if (toppos <= BUF_BEGV (b))
- sprintf (buf, "Top%2d%%", total);
- else
- sprintf (buf, "%2d%%", total);
-
- Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
-
- goto decode_mode_spec_done;
- }
- break;
- }
-
- /* print % */
- case '%':
- str = "%";
- break;
-
- /* print one [ for each recursive editing level. */
- case '[':
- {
- int i;
-
- if (command_loop_level > 5)
- {
- str = "[[[... ";
- break;
- }
-
- for (i = 0; i < command_loop_level; i++)
- Dynarr_add (mode_spec, '[');
-
- goto decode_mode_spec_done;
- }
-
- /* print one ] for each recursive editing level. */
- case ']':
- {
- int i;
-
- if (command_loop_level > 5)
- {
- str = "...]]]";
- break;
- }
-
- for (i = 0; i < command_loop_level; i++)
- Dynarr_add (mode_spec, ']');
-
- goto decode_mode_spec_done;
- }
-
- /* print infinitely many dashes -- handle at top level now */
- case '-':
- break;
-
- }
-
- if (STRINGP (obj))
- Dynarr_add_many (mode_spec, string_data (XSTRING (obj)),
- string_length (XSTRING (obj)));
- else if (str)
- Dynarr_add_many (mode_spec, (Bufbyte *) str, strlen (str));
-
- decode_mode_spec_done:
- Dynarr_add (mode_spec, '\0');
- }
-
- /*****************************************************************************
- free_display_line
-
- Given a display line, free all if its data structures.
- ****************************************************************************/
- static void
- free_display_line (struct display_line *dl)
- {
- int block;
-
- if (dl->display_blocks)
- {
- for (block = 0; block < Dynarr_largest (dl->display_blocks); block++)
- {
- struct display_block *db = Dynarr_atp (dl->display_blocks, block);
-
- Dynarr_free (db->runes);
- }
-
- Dynarr_free (dl->display_blocks);
- dl->display_blocks = 0;
- }
-
- if (dl->left_glyphs)
- {
- Dynarr_free (dl->left_glyphs);
- dl->left_glyphs = 0;
- }
-
- if (dl->right_glyphs)
- {
- Dynarr_free (dl->right_glyphs);
- dl->right_glyphs = 0;
- }
- }
-
-
- /*****************************************************************************
- free_display_lines
-
- Given an array of display lines, free them and all data structures
- contained within them.
- ****************************************************************************/
- static void
- free_display_lines (display_line_dynarr *dla)
- {
- int line;
-
- for (line = 0; line < Dynarr_largest (dla); line++)
- {
- free_display_line (Dynarr_atp (dla, line));
- }
-
- Dynarr_free (dla);
- }
-
- /*****************************************************************************
- free_display_structs
-
- Call internal free routine for each set of display lines.
- ****************************************************************************/
- void
- free_display_structs (struct window_mirror *mir)
- {
- if (mir->current_display_lines)
- {
- free_display_lines (mir->current_display_lines);
- mir->current_display_lines = 0;
- }
-
- if (mir->desired_display_lines)
- {
- free_display_lines (mir->desired_display_lines);
- mir->desired_display_lines = 0;
- }
-
- if (mir->cmotion_display_lines)
- {
- free_display_lines (mir->cmotion_display_lines);
- mir->cmotion_display_lines = 0;
- }
- }
-
-
- static void
- mark_redisplay_structs (display_line_dynarr *dla,
- void (*markobj) (Lisp_Object))
- {
- int line;
-
- for (line = 0; line < Dynarr_length (dla); line++)
- {
- int block, loop;
- struct display_line *dl = Dynarr_atp (dla, line);
-
- for (block = 0; block < Dynarr_length (dl->display_blocks); block++)
- {
- int rune;
- struct display_block *db = Dynarr_atp (dl->display_blocks, block);
-
- for (rune = 0; rune < Dynarr_length (db->runes); rune++)
- {
- struct rune *rb = Dynarr_atp (db->runes, rune);
-
- if (!NILP (rb->extent))
- ((markobj) (rb->extent));
- if (rb->type == DGLYPH && !NILP (rb->object.dglyph.glyph))
- ((markobj) (rb->object.dglyph.glyph));
- }
- }
-
- for (loop = 0; loop < 2; loop++)
- {
- glyph_block_dynarr *gba = (loop
- ? dl->right_glyphs
- : dl->left_glyphs);
-
- if (gba != NULL)
- {
- for (block = 0; block < Dynarr_length (gba); block++)
- {
- struct glyph_block *gb = Dynarr_atp (gba, block);
-
- if (!NILP (gb->glyph))
- ((markobj) (gb->glyph));
- if (!NILP (gb->extent))
- ((markobj) (gb->extent));
- }
- }
- }
- }
- }
-
- static void
- mark_window_mirror (struct window_mirror *mir, void (*markobj)(Lisp_Object))
- {
- mark_redisplay_structs (mir->current_display_lines, markobj);
- mark_redisplay_structs (mir->desired_display_lines, markobj);
- mark_redisplay_structs (mir->cmotion_display_lines, markobj);
-
- if (mir->next)
- mark_window_mirror (mir->next, markobj);
-
- if (mir->hchild)
- mark_window_mirror (mir->hchild, markobj);
- else if (mir->vchild)
- mark_window_mirror (mir->vchild, markobj);
- }
-
- void
- mark_redisplay (void (*markobj)(Lisp_Object))
- {
- Lisp_Object device;
-
- DEVICE_LOOP (device)
- {
- Lisp_Object rest;
-
- if (!gc_record_type_p (XCAR (device), lrecord_device))
- abort (); /* ASSERT - all Vdevice_list entries must be devices */
-
- for (rest = DEVICE_FRAME_LIST (XDEVICE (XCAR (device)));
- !NILP (rest);
- rest = XCDR (rest))
- {
- Lisp_Object frame = XCAR (rest);
- struct frame *f;
- if (! gc_record_type_p (frame, lrecord_frame))
- abort ();
- f = XFRAME (XCAR (rest));
- update_frame_window_mirror (f);
- mark_window_mirror (f->root_mirror, markobj);
- }
- }
- }
-
- /*****************************************************************************
- Line Start Cache Description and Rationale
-
- The traditional scrolling code in Emacs breaks in a variable height world.
- It depends on the key assumption that the number of lines that can be
- displayed at any given time is fixed. This led to a complete separation
- of the scrolling code from the redisplay code. In order to fully support
- variable height lines, the scrolling code must actually be tightly
- integrated with redisplay. Only redisplay can determine how many lines
- will be displayed on a screen for any given starting point.
-
- What is ideally wanted is a complete list of the starting buffer position
- for every possible display line of a buffer along with the height of that
- display line. Maintaining such a full list would be very expensive. We
- settle for having it include information for all areas which we happen to
- generate anyhow (i.e. the region currently being displayed) and for those
- areas we need to work with.
-
- In order to ensure that the cache accurately represents what redisplay
- would actually show, it is necessary to invalidate it in many situations.
- If the buffer changes, the starting positions may no longer be correct.
- If a face or an extent has changed then the line heights may have altered.
- These events happen frequently enough that the cache can end up being
- constantly disabled. With this potentially constant invalidation when is
- the cache ever useful?
-
- Even if the cache is invalidated before every single usage, it is
- necessary. Scrolling often requires knowledge about display lines which
- are actually above or below the visible region. The cache provides a
- convenient light-weight method of storing this information for multiple
- display regions. This knowledge is necessary for the scrolling code to
- always obey the First Golden Rule of Redisplay.
-
- If the cache already contains all of the information that the scrolling
- routines happen to need so that it doesn't have to go generate it, then we
- are able to obey the Third Golden Rule of Redisplay. The first thing we
- do to help out the cache is to always add the displayed region. This
- region had to be generated anyway, so the cache ends up getting the
- information basically for free. In those cases where a user is simply
- scrolling around viewing a buffer there is a high probability that this is
- sufficient to always provide the needed information. The second thing we
- can do is be smart about invalidating the cache.
-
- TODO -- Be smart about invalidating the cache. Potential places:
-
- + Insertions at end-of-line which don't cause line-wraps do not alter the
- starting positions of any display lines. These types of buffer
- modifications should not invalidate the cache. This is actually a large
- optimization for redisplay speed as well.
-
- + Buffer modifications frequently only affect the display of lines at and
- below where they occur. In these situations we should only invalidate
- the part of the cache starting at where the modification occurs.
-
- In case you're wondering, the Second Golden Rule of Redisplay is not
- applicable.
- ****************************************************************************/
-
- /* This will get used quite a bit so we don't want to be constantly
- allocating and freeing it. */
- line_start_cache_dynarr *internal_cache;
-
- /*****************************************************************************
- update_internal_cache_list
-
- Makes internal_cache represent the TYPE display structs and only the
- TYPE display structs.
- ****************************************************************************/
- static void
- update_internal_cache_list (struct window *w, int type)
- {
- int line;
- display_line_dynarr *dla = window_display_lines (w, type);
-
- Dynarr_reset (internal_cache);
- for (line = 0; line < Dynarr_length (dla); line++)
- {
- struct display_line *dl = Dynarr_atp (dla, line);
-
- if (dl->modeline)
- continue;
- else
- {
- struct line_start_cache lsc;
-
- lsc.start = dl->bufpos;
- lsc.end = dl->end_bufpos;
- lsc.height = dl->ascent + dl->descent;
-
- Dynarr_add (internal_cache, lsc);
- }
- }
- }
-
- /*****************************************************************************
- validate_line_start_cache
-
- Reset the line cache if necessary. This should be run at the
- beginning of any function which access the cache.
- ****************************************************************************/
- static void
- validate_line_start_cache (struct window *w)
- {
- struct buffer *b = XBUFFER (w->buffer);
- struct frame *f = XFRAME (w->frame);
-
- if (!w->line_cache_validation_override)
- {
- /* f->extents_changed used to be in here because extent face and
- size changes can cause text shifting. However, the extent
- covering the region is constantly having its face set and
- priority altered by the mouse code. This means that the line
- start cache is constanty being invalidated. This is bad
- since the mouse code also triggers heavy usage of the cache.
- Since it is an unlikely that f->extents being changed
- indicates that the cache really needs to be updated and if it
- does redisplay will catch it pretty quickly we no longer
- invalidate the cache if it is set. This greatly speeds up
- dragging out regions with the mouse. */
- if (XINT (w->line_cache_last_updated) < BUF_MODIFF (b)
- || f->faces_changed
- || f->clip_changed)
- {
- Dynarr_reset (w->line_start_cache);
- }
- }
- }
-
- /*****************************************************************************
- line_start_cache_start
-
- Return the very first buffer position contained in the given window's
- cache, or -1 if the cache is empty. Assumes that the cache is valid.
- ****************************************************************************/
- static Bufpos
- line_start_cache_start (struct window *w)
- {
- line_start_cache_dynarr *cache = w->line_start_cache;
-
- if (!Dynarr_length (cache))
- return -1;
- else
- return (Dynarr_atp (cache, 0)->start);
- }
-
- /*****************************************************************************
- line_start_cache_end
-
- Return the very last buffer position contained in the given window's
- cache, or -1 if the cache is empty. Assumes that the cache is valid.
- ****************************************************************************/
- static Bufpos
- line_start_cache_end (struct window *w)
- {
- line_start_cache_dynarr *cache = w->line_start_cache;
-
- if (!Dynarr_length (cache))
- return -1;
- else
- return (Dynarr_atp (cache, Dynarr_length (cache) - 1)->end);
- }
-
- /*****************************************************************************
- point_in_line_start_cache
-
- Return the index of the line POINT is contained within in window W's line
- start cache. It will enlarge the cache or move the cache window in order
- to have POINT be present in the cache. MIN_PAST is a guarantee of the
- number of entries in the cache present on either side of POINT (unless a
- buffer boundary is hit). If MIN_PAST is -1 then it will be treated as 0,
- but the cache window will not be allowed to shift. Returns -1 if POINT
- cannot be found in the cache for any reason.
- ****************************************************************************/
- int
- point_in_line_start_cache (struct window *w, Bufpos point, int min_past)
- {
- struct buffer *b = XBUFFER (w->buffer);
- line_start_cache_dynarr *cache = w->line_start_cache;
- unsigned int top, bottom, pos;
-
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
-
- /* Let functions pass in negative values, but we still treat -1
- specially. */
- /* #### bogosity alert */
- if (min_past < 0 && min_past != -1)
- min_past = -min_past;
-
- if (!Dynarr_length (cache) || line_start_cache_start (w) > point
- || line_start_cache_end (w) < point)
- {
- int loop;
- int win_char_height = window_char_height (w, 1);
-
- /* Occasionally we get here with a 0 height
- window. find_next_newline_no_quit will abort if we pass it a
- count of 0 so handle that case. */
- if (!win_char_height)
- win_char_height = 1;
-
- if (!Dynarr_length (cache))
- {
- Bufpos from = find_next_newline_no_quit (b, point, -1);
- Bufpos to = find_next_newline_no_quit (b, from, win_char_height);
-
- update_line_start_cache (w, from, to, point, 0);
-
- if (!Dynarr_length (cache))
- {
- w->line_cache_validation_override--;
- return -1;
- }
- }
-
- assert (Dynarr_length (cache));
-
- loop = 0;
- while (line_start_cache_start (w) > point
- && (loop < cache_adjustment || min_past == -1))
- {
- Bufpos from, to;
-
- from = line_start_cache_start (w);
- if (from <= BUF_BEGV (b))
- break;
-
- from = find_next_newline_no_quit (b, from, -win_char_height);
- to = line_start_cache_end (w);
-
- update_line_start_cache (w, from, to, point, 0);
- loop++;
- }
-
- if (line_start_cache_start (w) > point)
- {
- Bufpos from, to;
-
- from = find_next_newline_no_quit (b, point, -1);
- if (from >= BUF_ZV (b))
- {
- to = find_next_newline_no_quit (b, from, -win_char_height);
- from = to;
- to = BUF_ZV (b);
- }
- else
- to = find_next_newline_no_quit (b, from, win_char_height);
-
- update_line_start_cache (w, from, to, point, 0);
- }
-
- loop = 0;
- while (line_start_cache_end (w) < point
- && (loop < cache_adjustment || min_past == -1))
- {
- Bufpos from, to;
-
- to = line_start_cache_end (w);
- if (to >= BUF_ZV (b))
- break;
-
- from = line_start_cache_end (w);
- to = find_next_newline_no_quit (b, from, win_char_height);
-
- update_line_start_cache (w, from, to, point, 0);
- loop++;
- }
-
- if (line_start_cache_end (w) < point)
- {
- Bufpos from, to;
-
- from = find_next_newline_no_quit (b, point, -1);
- if (from >= BUF_ZV (b))
- {
- to = find_next_newline_no_quit (b, from, -win_char_height);
- from = to;
- to = BUF_ZV (b);
- }
- else
- to = find_next_newline_no_quit (b, from, win_char_height);
-
- update_line_start_cache (w, from, to, point, 0);
- }
- }
-
- assert (Dynarr_length (cache));
-
- if (min_past == -1)
- min_past = 0;
-
- /* This could happen if the buffer is narrowed. */
- if (line_start_cache_start (w) > point
- || line_start_cache_end (w) < point)
- {
- w->line_cache_validation_override--;
- return -1;
- }
-
- find_point_loop:
-
- top = Dynarr_length (cache) - 1;
- bottom = 0;
-
- while (1)
- {
- unsigned int new_pos;
- Bufpos start, end;
-
- pos = (bottom + top + 1) >> 1;
- start = Dynarr_atp (cache, pos)->start;
- end = Dynarr_atp (cache, pos)->end;
-
- if (point >= start && point <= end)
- {
- if (pos < min_past && line_start_cache_start (w) > BUF_BEGV (b))
- {
- Bufpos from =
- find_next_newline_no_quit (b, line_start_cache_start (w),
- -min_past - 1);
- Bufpos to = line_start_cache_end (w);
-
- update_line_start_cache (w, from, to, point, 0);
- goto find_point_loop;
- }
- else if ((Dynarr_length (cache) - pos - 1) < min_past
- && line_start_cache_end (w) < BUF_ZV (b))
- {
- Bufpos from = line_start_cache_end (w);
- Bufpos to = find_next_newline_no_quit (b, from,
- (min_past
- ? min_past
- : 1));
-
- update_line_start_cache (w, from, to, point, 0);
- goto find_point_loop;
- }
- else
- {
- w->line_cache_validation_override--;
- return pos;
- }
- }
- else if (point > end)
- bottom = pos + 1;
- else if (point < start)
- top = pos - 1;
- else
- abort ();
-
- new_pos = (bottom + top + 1) >> 1;
- if (pos == new_pos)
- {
- w->line_cache_validation_override--;
- return -1;
- }
- }
- }
-
- /*****************************************************************************
- point_would_be_visible
-
- Return a boolean indicating if POINT would be visible in window W if
- display of the window was to begin at STARTP.
- ****************************************************************************/
- int
- point_would_be_visible (struct window *w, Bufpos startp, Bufpos point)
- {
- struct buffer *b = XBUFFER (w->buffer);
- int pixpos = 0;
- int bottom = WINDOW_TEXT_HEIGHT (w);
- int start_elt;
-
- /* If point is before the intended start it obviously can't be visible. */
- if (point < startp)
- return 0;
-
- /* If point or start are not in the accessible buffer range, then
- fail. */
- if (startp < BUF_BEGV (b) || startp > BUF_ZV (b)
- || point < BUF_BEGV (b) || point > BUF_ZV (b))
- {
- w->line_cache_validation_override--;
- return 0;
- }
-
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
-
- start_elt = point_in_line_start_cache (w, startp, 0);
- if (start_elt == -1)
- {
- w->line_cache_validation_override--;
- return 0;
- }
-
- assert (line_start_cache_start (w) <= startp
- && line_start_cache_end (w) >= startp);
-
- while (1)
- {
- int height;
-
- /* Expand the cache if necessary. */
- if (start_elt == Dynarr_length (w->line_start_cache))
- {
- Bufpos old_startp =
- Dynarr_atp (w->line_start_cache, start_elt - 1)->start;
-
- start_elt = point_in_line_start_cache (w, old_startp,
- window_char_height (w, 0));
-
- /* We've already actually processed old_startp, so increment
- immediately. */
- start_elt++;
-
- /* If this happens we didn't add any extra elements. Bummer. */
- if (start_elt == Dynarr_length (w->line_start_cache))
- {
- w->line_cache_validation_override--;
- return 0;
- }
- }
-
- height = Dynarr_atp (w->line_start_cache, start_elt)->height;
-
- if (pixpos + height > bottom)
- {
- if (bottom - pixpos < VERTICAL_CLIP (w, 0))
- {
- w->line_cache_validation_override--;
- return 0;
- }
- }
-
- pixpos += height;
- if (point <= Dynarr_atp (w->line_start_cache, start_elt)->end)
- {
- w->line_cache_validation_override--;
- return 1;
- }
-
- start_elt++;
- }
- }
-
- /*****************************************************************************
- start_end_of_last_line
-
- For the given window W, if display starts at STARTP, what will be the
- buffer position at the beginning or end of the last line displayed.
- The end of the last line is also know as the window end position.
-
- #### With a little work this could probably be reworked as just a call to
- start_with_line_at_pixpos.
- ****************************************************************************/
- static Bufpos
- start_end_of_last_line (struct window *w, Bufpos startp, int end)
- {
- struct buffer *b = XBUFFER (w->buffer);
- line_start_cache_dynarr *cache = w->line_start_cache;
- int pixpos = 0;
- int bottom = WINDOW_TEXT_HEIGHT (w);
- Bufpos cur_start;
- int start_elt;
-
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
-
- if (startp < BUF_BEGV (b))
- startp = BUF_BEGV (b);
- else if (startp > BUF_ZV (b))
- startp = BUF_ZV (b);
- cur_start = startp;
-
- start_elt = point_in_line_start_cache (w, cur_start, 0);
- if (start_elt == -1)
- abort (); /* this had better never happen */
-
- while (1)
- {
- int height = Dynarr_atp (cache, start_elt)->height;
-
- cur_start = Dynarr_atp (cache, start_elt)->start;
-
- if (pixpos + height > bottom)
- {
- /* Adjust for any possible clip. */
- if (bottom - pixpos < VERTICAL_CLIP (w, 0))
- start_elt--;
-
- if (start_elt < 0)
- {
- w->line_cache_validation_override--;
- if (end)
- return (BUF_ZV (b));
- else
- return (BUF_BEGV (b));
- }
- else
- {
- w->line_cache_validation_override--;
- if (end)
- return Dynarr_atp (cache, start_elt)->end;
- else
- return Dynarr_atp (cache, start_elt)->start;
- }
- }
-
- pixpos += height;
- start_elt++;
- if (start_elt == Dynarr_length (cache))
- {
- Bufpos from = line_start_cache_end (w);
- int win_char_height = window_char_height (w, 0);
- Bufpos to = find_next_newline_no_quit (b, from,
- (win_char_height
- ? win_char_height
- : 1));
-
- /* We've hit the end of the bottom so that's what it is. */
- if (from >= BUF_ZV (b))
- {
- w->line_cache_validation_override--;
- return (BUF_ZV (b));
- }
-
- update_line_start_cache (w, from, to, BUF_PT (b), 0);
-
- /* Updating the cache invalidates any current indexes. */
- start_elt = point_in_line_start_cache (w, cur_start, -1) + 1;
- }
- }
- }
-
- /*****************************************************************************
- start_of_last_line
-
- For the given window W, if display starts at STARTP, what will be the
- buffer position at the beginning of the last line displayed.
- ****************************************************************************/
- Bufpos
- start_of_last_line (struct window *w, Bufpos startp)
- {
- return start_end_of_last_line (w, startp, 0);
- }
-
- /*****************************************************************************
- end_of_last_line
-
- For the given window W, if display starts at STARTP, what will be the
- buffer position at the end of the last line displayed. This is also
- know as the window end position.
- ****************************************************************************/
- Bufpos
- end_of_last_line (struct window *w, Bufpos startp)
- {
- return start_end_of_last_line (w, startp, 1);
- }
-
- /*****************************************************************************
- start_with_line_at_pixpos
-
- For window W, what does the starting position have to be so that the line
- containing POINT will cover pixel position PIXPOS.
- ****************************************************************************/
- Bufpos
- start_with_line_at_pixpos (struct window *w, Bufpos point, int pixpos)
- {
- struct buffer *b = XBUFFER (w->buffer);
- int cur_elt;
- Bufpos cur_pos;
- int pixheight = pixpos - WINDOW_TEXT_TOP (w);
-
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
-
- cur_elt = point_in_line_start_cache (w, point, 0);
- while (1)
- {
- cur_pos = Dynarr_atp (w->line_start_cache, cur_elt)->start;
-
- pixheight -= Dynarr_atp (w->line_start_cache, cur_elt)->height;
-
- /* Do not take into account the value of vertical_clip here.
- That is the responsibility of the calling functions. */
- if (pixheight < 0)
- {
- w->line_cache_validation_override--;
- return cur_pos;
- }
-
- cur_elt--;
- if (cur_elt < 0)
- {
- Bufpos from, to;
- int win_char_height;
-
- if (cur_pos <= BUF_BEGV (b))
- {
- w->line_cache_validation_override--;
- return (BUF_BEGV (b));
- }
-
- win_char_height = window_char_height (w, 0);
- if (!win_char_height)
- win_char_height = 1;
-
- from = find_next_newline_no_quit (b, cur_pos, -win_char_height);
- to = line_start_cache_end (w);
- update_line_start_cache (w, from, to, point, 0);
-
- cur_elt = point_in_line_start_cache (w, cur_pos, 2) - 1;
- assert (cur_elt >= 0);
- }
- }
- }
-
- /*****************************************************************************
- start_with_point_on_display_line
-
- For window W, what does the starting position have to be so that the
- line containing point is on display line LINE. If LINE is positive
- it is considered to be the number of lines from the top of the window
- (0 is the top line). If it is negative the number is considered to
- be the number of lines from the bottom (-1 is the bottom line).
- ****************************************************************************/
- Bufpos
- start_with_point_on_display_line (struct window *w, Bufpos point, int line)
- {
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
-
- if (line >= 0)
- {
- int cur_elt = point_in_line_start_cache (w, point, line);
-
- if (cur_elt - line < 0)
- cur_elt = 0; /* Hit the top */
- else
- cur_elt -= line;
-
- w->line_cache_validation_override--;
- return (Dynarr_atp (w->line_start_cache, cur_elt)->start);
- }
- else
- {
- /* The calculated value of pixpos is correct for the bottom line
- or what we want when line is -1. Therefore we subtract one
- because we have already handled one line. */
- int new_line = -line - 1;
- int cur_elt = point_in_line_start_cache (w, point, new_line);
- int pixpos = WINDOW_TEXT_BOTTOM (w);
- Bufpos retval, search_point;
-
- /* If scroll_on_clipped_lines is false, the last "visible" line of
- the window covers the pixel at WINDOW_TEXT_BOTTOM (w) - 1.
- If s_o_c_l is true, then we don't want to count a clipped
- line, so back up from the bottom by the height of the line
- containing point. */
- if (scroll_on_clipped_lines)
- pixpos -= Dynarr_atp (w->line_start_cache, cur_elt)->height;
- else
- pixpos -= 1;
-
- if (cur_elt + new_line >= Dynarr_length (w->line_start_cache))
- {
- /* Hit the bottom of the buffer. */
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- struct font_metric_info fm;
- int adjustment =
- (cur_elt + new_line) - Dynarr_length (w->line_start_cache) + 1;
-
- cur_elt = Dynarr_length (w->line_start_cache) - 1;
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
- pixpos -= (adjustment * fm.height);
- if (pixpos < WINDOW_TEXT_TOP (w))
- pixpos = WINDOW_TEXT_TOP (w);
- }
- else
- cur_elt = cur_elt + new_line;
-
- search_point = Dynarr_atp (w->line_start_cache, cur_elt)->start;
-
- retval = start_with_line_at_pixpos (w, search_point, pixpos);
- w->line_cache_validation_override--;
- return retval;
- }
- }
-
- /*****************************************************************************
- update_line_start_cache
-
- This is used to speed up vertical scrolling by caching the known buffer
- starting positions for display lines. This allows the scrolling routines
- to avoid costly calls to regenerate_window. If NO_REGEN is true then it
- will only add the values in the DESIRED display structs which are in the
- given range.
-
- Note also that the FROM/TO values are minimums. It is possible that this
- function will actually add information outside of the lines containing
- those positions. This can't hurt but it could possibly help.
-
- #### We currently force the cache to have only 1 contiguous region. It
- might help to make the cache a dynarr of caches so that we can cover more
- areas. This might, however, turn out to be a lot of overhead for too
- little gain.
- ****************************************************************************/
- static void
- update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
- Bufpos point, int no_regen)
- {
- struct buffer *b = XBUFFER (w->buffer);
- line_start_cache_dynarr *cache = w->line_start_cache;
- Bufpos low_bound, high_bound;
-
- validate_line_start_cache (w);
- w->line_cache_validation_override++;
- updating_line_start_cache = 1;
-
- if (from < BUF_BEGV (b))
- from = BUF_BEGV (b);
- if (to > BUF_ZV (b))
- to = BUF_ZV (b);
-
- if (from > to)
- {
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- if (Dynarr_length (cache))
- {
- low_bound = line_start_cache_start (w);
- high_bound = line_start_cache_end (w);
-
- /* Check to see if the desired range is already in the cache. */
- if (from >= low_bound && to <= high_bound)
- {
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- /* Check to make sure that the desired range is adjacent to the
- current cache. If not, invalidate the cache. */
- if (to < low_bound || from > high_bound)
- {
- Dynarr_reset (cache);
- low_bound = high_bound = -1;
- }
- }
- else
- {
- low_bound = high_bound = -1;
- }
-
- w->line_cache_last_updated = make_number (BUF_MODIFF (b));
-
- /* This could be integrated into the next two sections, but it is easier
- to follow what's going on by having it separate. */
- if (no_regen)
- {
- Bufpos start, end;
-
- update_internal_cache_list (w, DESIRED_DISP);
- if (!Dynarr_length (internal_cache))
- {
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- start = Dynarr_atp (internal_cache, 0)->start;
- end =
- Dynarr_atp (internal_cache, Dynarr_length (internal_cache) - 1)->end;
-
- /* We aren't allowed to generate additional information to fill in
- gaps, so if the DESIRED structs don't overlap the cache, reset the
- cache. */
- if (Dynarr_length (cache))
- {
- if (end < low_bound || start > high_bound)
- Dynarr_reset (cache);
-
- /* #### What should really happen if what we are doing is
- extending a line (the last line)? */
- if (Dynarr_length (cache) == 1
- && Dynarr_length (internal_cache) == 1)
- Dynarr_reset (cache);
- }
-
- if (!Dynarr_length (cache))
- {
- Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
- Dynarr_length (internal_cache));
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- /* An extra check just in case the calling function didn't pass in
- the bounds of the DESIRED structs in the first place. */
- if (start >= low_bound && end <= high_bound)
- {
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- /* At this point we know that the internal cache partially overlaps
- the main cache. */
- if (start < low_bound)
- {
- int ic_elt = Dynarr_length (internal_cache) - 1;
- while (ic_elt >= 0)
- {
- if (Dynarr_atp (internal_cache, ic_elt)->start < low_bound)
- break;
- else
- ic_elt--;
- }
-
- if (!(ic_elt >= 0))
- {
- Dynarr_reset (cache);
- Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
- Dynarr_length (internal_cache));
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- Dynarr_insert_many_at_start (cache, Dynarr_atp (internal_cache, 0),
- ic_elt + 1);
- }
-
- if (end > high_bound)
- {
- int ic_elt = 0;
-
- while (ic_elt < Dynarr_length (internal_cache))
- {
- if (Dynarr_atp (internal_cache, ic_elt)->start > high_bound)
- break;
- else
- ic_elt++;
- }
-
- if (!(ic_elt < Dynarr_length (internal_cache)))
- {
- Dynarr_reset (cache);
- Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
- Dynarr_length (internal_cache));
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- Dynarr_add_many (cache, Dynarr_atp (internal_cache, ic_elt),
- Dynarr_length (internal_cache) - ic_elt);
- }
-
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
-
- if (!Dynarr_length (cache) || from < low_bound)
- {
- Bufpos startp = find_next_newline_no_quit (b, from, -1);
- int marker = 0;
- int old_lb = low_bound;
-
- while (startp < old_lb || low_bound == -1)
- {
- int ic_elt;
-
- regenerate_window (w, startp, point, CMOTION_DISP);
- update_internal_cache_list (w, CMOTION_DISP);
-
- /* If this assert is triggered then regenerate_window failed
- to layout a single line. That is not supposed to be
- possible because we impose a minimum height on the buffer
- and override vertical clip when we are in here. */
- assert (Dynarr_length (internal_cache));
- assert (startp == Dynarr_atp (internal_cache, 0)->start);
-
- ic_elt = Dynarr_length (internal_cache) - 1;
- if (low_bound != -1)
- {
- while (ic_elt >= 0)
- {
- if (Dynarr_atp (internal_cache, ic_elt)->start < old_lb)
- break;
- else
- ic_elt--;
- }
- }
- assert (ic_elt >= 0);
-
- Dynarr_insert_many (cache, Dynarr_atp (internal_cache, 0),
- ic_elt + 1, marker);
- marker += (ic_elt + 1);
-
- if (startp < low_bound || low_bound == -1)
- low_bound = startp;
- startp = Dynarr_atp (internal_cache, ic_elt)->end + 1;
- if (startp > BUF_ZV (b))
- {
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- return;
- }
- }
- }
-
- assert (Dynarr_length (cache));
- assert (from >= low_bound);
-
- /* Readjust the high_bound to account for any changes made while
- correcting the low_bound. */
- high_bound = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end;
-
- if (to > high_bound)
- {
- Bufpos startp = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end + 1;
-
- do
- {
- regenerate_window (w, startp, point, CMOTION_DISP);
- update_internal_cache_list (w, CMOTION_DISP);
-
- /* See comment above about regenerate_window failing. */
- assert (Dynarr_length (internal_cache));
-
- Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
- Dynarr_length (internal_cache));
- high_bound = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end;
- startp = high_bound + 1;
- }
- while (to > high_bound);
- }
-
- updating_line_start_cache = 0;
- w->line_cache_validation_override--;
- assert (to <= high_bound);
- }
-
-
- /*****************************************************************************
- glyph_to_pixel_translation
-
- Given x and y coordinates in characters, relative to a window, return the
- pixel location corresponding to those coordinates. The pixel location
- returned is the center of the given character position. The pixel values
- are generated relative to the window, not the frame.
-
- The modeline is considered to be part of the window.
- ****************************************************************************/
- void
- glyph_to_pixel_translation (struct window *w, int char_x, int char_y,
- int *pix_x, int *pix_y)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
- int num_disp_lines, modeline;
-
- /* If we get a bogus value indicating somewhere above or to the left of
- the window, use the first window line or character position
- instead. */
- if (char_y < 0)
- char_y = 0;
- if (char_x < 0)
- char_x = 0;
-
- num_disp_lines = Dynarr_length (dla);
- modeline = 0;
- if (num_disp_lines)
- {
- if (Dynarr_atp (dla, 0)->modeline)
- {
- num_disp_lines--;
- modeline = 1;
- }
- }
-
- /* First check if the y position intersects the display lines. */
- if (char_y < num_disp_lines)
- {
- struct display_line *dl = Dynarr_atp (dla, char_y + modeline);
- struct display_block *db = get_display_block_from_line (dl, TEXT);
-
- *pix_y = (dl->ypos - dl->ascent +
- ((unsigned int) (dl->ascent + dl->descent - dl->clip) >> 1));
-
- if (char_x < Dynarr_length (db->runes))
- {
- struct rune *rb = Dynarr_atp (db->runes, char_x);
-
- *pix_x = rb->xpos + (rb->width >> 1);
- }
- else
- {
- int last_rune = Dynarr_length (db->runes) - 1;
- struct rune *rb = Dynarr_atp (db->runes, last_rune);
- struct font_metric_info fm;
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
-
- char_x -= last_rune;
-
- *pix_x = rb->xpos + rb->width;
- *pix_x += ((char_x - 1) * fm.width);
- *pix_x += (fm.width >> 1);
- }
- }
- else
- {
- /* It didn't intersect, so extrapolate. #### For now, we include the
- modeline in this since we don't have true character positions in
- it. */
- struct font_metric_info fm;
-
- if (!Dynarr_length (w->face_cache_elements))
- reset_face_cache_elements (w);
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
-
- char_y -= num_disp_lines;
-
- if (Dynarr_length (dla))
- {
- struct display_line *dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
- *pix_y = dl->ypos + dl->descent - dl->clip;
- }
- else
- *pix_y = WINDOW_TEXT_TOP (w);
-
- *pix_y += (char_y * fm.height);
- *pix_y += (fm.height >> 1);
-
- *pix_x = WINDOW_TEXT_LEFT (w);
- /* Don't adjust by one because this is still the unadjusted value. */
- *pix_x += (char_x * fm.width);
- *pix_x += (fm.width >> 1);
- }
-
- if (*pix_x > w->pixel_left + w->pixel_width)
- *pix_x = w->pixel_left + w->pixel_width;
- if (*pix_y > w->pixel_top + w->pixel_height)
- *pix_y = w->pixel_top + w->pixel_height;
-
- *pix_x -= w->pixel_left;
- *pix_y -= w->pixel_top;
- }
-
- /*****************************************************************************
- get_position_object
-
- Given a display line and a position, determine if there is a glyph
- there and return information about it if there is.
- ****************************************************************************/
- static void
- get_position_object (struct display_line *dl, Lisp_Object *obj, int x_coord,
- int *low_x_coord, int *high_x_coord)
- {
- struct display_block *db;
- int elt;
- int block =
- get_next_display_block (dl->bounds, dl->display_blocks, x_coord, 0);
-
- /* We use get_next_display_block to get the actual display block
- that would be displayed at x_coord. */
-
- if (block == NO_BLOCK)
- return;
- else
- db = Dynarr_atp (dl->display_blocks, block);
-
- for (elt = 0; elt < Dynarr_length (db->runes); elt++)
- {
- struct rune *rb = Dynarr_atp (db->runes, elt);
-
- if (rb->xpos <= x_coord && x_coord < (rb->xpos + rb->width))
- {
- *obj = rb->extent;
- if (low_x_coord)
- *low_x_coord = rb->xpos;
- if (high_x_coord)
- *high_x_coord = rb->xpos + rb->width;
-
- return;
- }
- }
- }
-
- /*****************************************************************************
- pixel_to_glyph_translation
-
- Given x and y coordinates in pixels relative to a frame, return
- information about what is located under those coordinates.
- ****************************************************************************/
-
- #define UPDATE_CACHE_RETURN \
- do { \
- d->pixel_to_glyph_cache.valid = 1; \
- d->pixel_to_glyph_cache.low_x_coord = low_x_coord; \
- d->pixel_to_glyph_cache.high_x_coord = high_x_coord; \
- d->pixel_to_glyph_cache.low_y_coord = low_y_coord; \
- d->pixel_to_glyph_cache.high_y_coord = high_y_coord; \
- d->pixel_to_glyph_cache.frame = f; \
- d->pixel_to_glyph_cache.col = *col; \
- d->pixel_to_glyph_cache.row = *row; \
- d->pixel_to_glyph_cache.obj_x = *obj_x; \
- d->pixel_to_glyph_cache.obj_y = *obj_y; \
- d->pixel_to_glyph_cache.w = *w; \
- d->pixel_to_glyph_cache.bufpos = *bufpos; \
- d->pixel_to_glyph_cache.closest = *closest; \
- d->pixel_to_glyph_cache.obj = *obj; \
- d->pixel_to_glyph_cache.retval = position; \
- return position; \
- } while (0)
-
- int
- pixel_to_glyph_translation (struct frame *f, int x_coord, int y_coord,
- int *col, int *row, int *obj_x, int *obj_y,
- struct window **w, Bufpos *bufpos,
- Bufpos *closest, Lisp_Object *obj)
- {
- struct device *d;
- struct pixel_to_glyph_translation_cache *cache;
- Lisp_Object window;
- int frm_left, frm_right, frm_top, frm_bottom;
- int low_x_coord, high_x_coord, low_y_coord, high_y_coord;
- int position = OVER_NOTHING;
- int device_check_failed = 0;
- display_line_dynarr *dla;
-
- /* This is a safety valve in case this got called with a frame in
- the middle of being deleted. */
- if (!DEVICEP (f->device) || !DEVICE_LIVE_P (XDEVICE (f->device)))
- device_check_failed = 1;
- else
- {
- d = XDEVICE (f->device);
- cache = &d->pixel_to_glyph_cache;
- }
-
- if (!device_check_failed
- && cache->valid
- && cache->frame == f
- && cache->low_x_coord <= x_coord
- && cache->high_x_coord > x_coord
- && cache->low_y_coord <= y_coord
- && cache->high_y_coord > y_coord)
- {
- *col = cache->col;
- *row = cache->row;
- *obj_x = cache->obj_x;
- *obj_y = cache->obj_y;
- *w = cache->w;
- *bufpos = cache->bufpos;
- *closest = cache->closest;
- *obj = cache->obj;
-
- return cache->retval;
- }
- else
- {
- *col = 0;
- *row = 0;
- *obj_x = 0;
- *obj_y = 0;
- *w = 0;
- *bufpos = 0;
- *closest = 0;
- *obj = Qnil;
-
- low_x_coord = x_coord;
- high_x_coord = x_coord + 1;
- low_y_coord = y_coord;
- high_y_coord = y_coord + 1;
- }
-
- if (device_check_failed)
- return OVER_NOTHING;
-
- frm_left = FRAME_LEFT_BORDER_END (f);
- frm_right = FRAME_RIGHT_BORDER_START (f);
- frm_top = FRAME_TOP_BORDER_END (f);
- frm_bottom = FRAME_BOTTOM_BORDER_START (f);
-
- /* Check if the mouse is outside of the text area actually used by
- redisplay. */
- if (y_coord < frm_top)
- {
- if (y_coord >= FRAME_TOP_BORDER_START (f))
- {
- low_y_coord = FRAME_TOP_BORDER_START (f);
- high_y_coord = frm_top;
- position = OVER_BORDER;
- }
- else if (y_coord >= 0)
- {
- low_y_coord = 0;
- high_y_coord = FRAME_TOP_BORDER_START (f);
- position = OVER_TOOLBAR;
- }
- else
- {
- low_y_coord = y_coord;
- high_y_coord = 0;
- position = OVER_OUTSIDE;
- }
- }
- else if (y_coord >= frm_bottom)
- {
- if (y_coord < FRAME_BOTTOM_BORDER_END (f))
- {
- low_y_coord = frm_bottom;
- high_y_coord = FRAME_BOTTOM_BORDER_END (f);
- position = OVER_BORDER;
- }
- else if (y_coord < FRAME_PIXHEIGHT (f))
- {
- low_y_coord = FRAME_BOTTOM_BORDER_END (f);
- high_y_coord = FRAME_PIXHEIGHT (f);
- position = OVER_TOOLBAR;
- }
- else
- {
- low_y_coord = FRAME_PIXHEIGHT (f);
- high_y_coord = y_coord;
- position = OVER_OUTSIDE;
- }
- }
-
- if (position != OVER_TOOLBAR && position != OVER_BORDER)
- {
- if (x_coord < frm_left)
- {
- if (x_coord >= FRAME_LEFT_BORDER_START (f))
- {
- low_x_coord = FRAME_LEFT_BORDER_START (f);
- high_x_coord = frm_left;
- position = OVER_BORDER;
- }
- else if (x_coord >= 0)
- {
- low_x_coord = 0;
- high_x_coord = FRAME_LEFT_BORDER_START (f);
- position = OVER_TOOLBAR;
- }
- else
- {
- low_x_coord = x_coord;
- high_x_coord = 0;
- position = OVER_OUTSIDE;
- }
- }
- else if (x_coord >= frm_right)
- {
- if (x_coord < FRAME_RIGHT_BORDER_END (f))
- {
- low_x_coord = frm_right;
- high_x_coord = FRAME_RIGHT_BORDER_END (f);
- position = OVER_BORDER;
- }
- else if (x_coord < FRAME_PIXWIDTH (f))
- {
- low_x_coord = FRAME_RIGHT_BORDER_END (f);
- high_x_coord = FRAME_PIXWIDTH (f);
- position = OVER_TOOLBAR;
- }
- else
- {
- low_x_coord = FRAME_PIXWIDTH (f);
- high_x_coord = x_coord;
- position = OVER_OUTSIDE;
- }
- }
- }
-
- if (position == OVER_TOOLBAR)
- {
- *obj = toolbar_button_at_pixpos (f, x_coord, y_coord);
- *w = 0;
- UPDATE_CACHE_RETURN;
- }
-
- /* We still have to return the window the pointer is next to and its
- relative y position even if it is outside the x boundary. */
- if (x_coord < frm_left)
- x_coord = frm_left;
- else if (x_coord > frm_right)
- x_coord = frm_right;
-
- /* Same in reverse. */
- if (y_coord < frm_top)
- y_coord = frm_top;
- else if (y_coord > frm_bottom)
- y_coord = frm_bottom;
-
- /* Find what window the given coordinates are actually in. */
- window = f->root_window;
- *w = find_window_by_pixel_pos (x_coord, y_coord, window);
-
- /* If we didn't find a window, we're done. */
- if (!*w)
- {
- UPDATE_CACHE_RETURN;
- }
- else if (position != OVER_NOTHING)
- {
- *closest = 0;
-
- if (high_y_coord <= frm_top || high_y_coord >= frm_bottom)
- {
- *w = 0;
- UPDATE_CACHE_RETURN;
- }
- }
-
- /* Check if the window is a minibuffer but isn't active. */
- if (MINI_WINDOW_P (*w) && !minibuf_level)
- {
- /* Must reset the window value since some callers will ignore
- the return value if it is set. */
- *w = 0;
- UPDATE_CACHE_RETURN;
- }
-
- dla = window_display_lines (*w, CURRENT_DISP);
-
- for (*row = 0; *row < Dynarr_length (dla); (*row)++)
- {
- int really_over_nothing = 0;
- struct display_line *dl = Dynarr_atp (dla, *row);
-
- if ((int) (dl->ypos - dl->ascent) <= y_coord
- && y_coord <= (int) (dl->ypos + dl->descent))
- {
- int check_margin_glyphs = 0;
- struct display_block *db = get_display_block_from_line (dl, TEXT);
- struct rune *rb = 0;
-
- if (x_coord < dl->bounds.left_white
- || x_coord >= dl->bounds.right_white)
- check_margin_glyphs = 1;
-
- low_y_coord = dl->ypos - dl->ascent;
- high_y_coord = dl->ypos + dl->descent + 1;
-
- if (position == OVER_BORDER
- || position == OVER_OUTSIDE
- || check_margin_glyphs)
- {
- int x_check, left_bound;
-
- if (check_margin_glyphs)
- {
- x_check = x_coord;
- left_bound = dl->bounds.left_white;
- }
- else
- {
- x_check = high_x_coord;
- left_bound = frm_left;
- }
-
- if (Dynarr_length (db->runes))
- {
- if (x_check <= left_bound)
- *closest = Dynarr_atp (db->runes, 0)->bufpos;
- else
- *closest =
- Dynarr_atp (db->runes,
- Dynarr_length (db->runes) - 1)->bufpos;
-
- *closest += dl->offset;
- }
- else
- {
- /* #### What should be here. */
- *closest = 0;
- }
-
- if (check_margin_glyphs)
- {
- if (x_coord < dl->bounds.left_in
- || x_coord >= dl->bounds.right_in)
- {
- /* If we are over the outside margins then we
- know the loop over the text block isn't going
- to accomplish anything. So we go ahead and
- set what information we can right here and
- return. */
- (*row)--;
- *obj_y = y_coord - (dl->ypos - dl->ascent);
- get_position_object (dl, obj, x_coord, &low_x_coord,
- &high_x_coord);
-
- UPDATE_CACHE_RETURN;
- }
- }
- else
- UPDATE_CACHE_RETURN;
- }
-
- for (*col = 0; *col <= Dynarr_length (db->runes); (*col)++)
- {
- int past_end = (*col == Dynarr_length (db->runes));
-
- if (!past_end)
- rb = Dynarr_atp (db->runes, *col);
-
- if (past_end ||
- (rb->xpos <= x_coord && x_coord < rb->xpos + rb->width))
- {
- if (past_end)
- {
- (*col)--;
- rb = Dynarr_atp (db->runes, *col);
- }
-
- *bufpos = rb->bufpos + dl->offset;
- low_x_coord = rb->xpos;
- high_x_coord = rb->xpos + rb->width;
-
- if (rb->type == DGLYPH)
- {
- int elt = *col + 1;
-
- /* Find the first character after the glyph. */
- while (elt < Dynarr_length (db->runes))
- {
- if (Dynarr_atp (db->runes, elt)->type != DGLYPH)
- {
- *closest = (Dynarr_atp (db->runes, elt)->bufpos +
- dl->offset);
- break;
- }
-
- elt++;
- }
-
- /* In this case we failed to find a non-glyph
- character so we return the last position
- displayed on the line. */
- if (elt == Dynarr_length (db->runes))
- {
- *closest = dl->end_bufpos + dl->offset;
- really_over_nothing = 1;
- }
- }
- else
- *closest = rb->bufpos + dl->offset;
-
- if (dl->modeline)
- {
- *row = window_displayed_height (*w);
-
- if (position == OVER_NOTHING)
- position = OVER_MODELINE;
-
- UPDATE_CACHE_RETURN;
- }
- else if (past_end
- || (rb->type == CHAR && rb->object.ch == '\n'))
- {
- (*row)--;
- /* At this point we may have glyphs in the right
- inside margin. */
- if (check_margin_glyphs)
- get_position_object (dl, obj, x_coord, &low_x_coord,
- &high_x_coord);
- UPDATE_CACHE_RETURN;
- }
- else
- {
- (*row)--;
- *obj = rb->extent;
- *obj_x = x_coord - rb->xpos;
- *obj_y = y_coord - (dl->ypos - dl->ascent);
-
- /* At this point we may have glyphs in the left
- inside margin. */
- if (check_margin_glyphs)
- get_position_object (dl, obj, x_coord, 0, 0);
-
- if (position == OVER_NOTHING && !really_over_nothing)
- position = OVER_TEXT;
-
- UPDATE_CACHE_RETURN;
- }
- }
- }
- }
- }
-
- *row = Dynarr_length (dla) - 1;
- if (FRAME_IS_WIN (f))
- {
- int bot_elt = Dynarr_length (dla) - 1;
-
- if (bot_elt >= 0)
- {
- struct display_line *dl = Dynarr_atp (dla, bot_elt);
- int adj_area = y_coord - (dl->ypos + dl->descent);
- struct font_metric_info fm;
-
- DEVMETH (d, font_metric_info,
- (d, FACE_CACHE_ELEMENT_FONT ((*w), DEFAULT_INDEX), &fm));
-
- *row += (adj_area / (fm.ascent + fm.descent));
- }
- }
-
- /* #### This should be checked out some more to determine what
- should really be going on. */
- if (!MARKERP ((*w)->start[CURRENT_DISP]))
- *closest = 0;
- else
- *closest = end_of_last_line (*w,
- marker_position ((*w)->start[CURRENT_DISP]));
- *col = 0;
- UPDATE_CACHE_RETURN;
- }
- #undef UPDATE_CACHE_RETURN
-
- DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
- "Clear frame FRAME and output again what is supposed to appear on it.")
- (frame)
- Lisp_Object frame;
- {
- CHECK_LIVE_FRAME (frame, 0);
-
- XFRAME (frame)->clear = 1;
- redisplay_frame (XFRAME (frame));
-
- return Qnil;
- }
-
- DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 1, 0,
- "Redraw all frames on DEVICE marked as having their image garbled.\n\
- DEVICE defaults to the selected device.\n\
- If DEVICE is t, all devices will have their frames checked.")
- (device)
- Lisp_Object device;
- {
- if (EQ (device, Qt))
- redisplay ();
- else
- redisplay_device (get_device (device));
-
- return Qnil;
- }
-
- /* Big lie. Big lie. This will force all modelines to be updated
- regardless if the all flag is set or not. It remains in existence
- solely for backwards compatibility. */
- DEFUN ("redraw-modeline", Fredraw_modeline, Sredraw_modeline, 0, 1, 0,
- "Force the modeline of the current buffer to be redisplayed.\n\
- With optional non-nil ALL, force redisplay of all modelines.")
- (all)
- Lisp_Object all;
- {
- MARK_MODELINE_CHANGED;
- return Qnil;
- }
-
- DEFUN ("force-redisplay", Fforce_redisplay, Sforce_redisplay, 0, 0, "",
- "Force an immediate redisplay of all frames.\n\
- Will still cause a redisplay when there is input pending (unlike when\n\
- the display is updated from `next-event'). This function differs from\n\
- `redraw-display' in that it causes an immediate, visible update of the\n\
- display's contents. Unlike `redraw-frame' or `recenter', it does not\n\
- mark any frame's current contents as invalid.")
- ()
- {
- /* redisplay() can't throw, right? It better not ... */
- disable_preemption++;
- redisplay ();
- disable_preemption--;
- return Qnil;
- }
-
- DEFUN ("force-cursor-redisplay", Fforce_cursor_redisplay,
- Sforce_cursor_redisplay, 0, 0, 0,
- "Force an immediate update of the cursor on the selected frame.")
- ()
- {
- redisplay_redraw_cursor (get_frame (Qnil), 1);
- return Qnil;
- }
-
-
- static void
- margin_width_changed_in_frame (Lisp_Object specifier, struct frame *f,
- Lisp_Object oldval)
- {
- /* Nothing to be done? */
- }
-
- int
- redisplay_variable_changed (Lisp_Object sym, Lisp_Object *val,
- struct buffer *b, int flags)
- {
- /* #### clip_changed should really be renamed something like
- global_redisplay_change. */
- MARK_CLIP_CHANGED;
- return 0;
- }
-
-
- void
- init_redisplay (void)
- {
- disable_preemption = 0;
- preemption_count = 0;
- max_preempts = INIT_MAX_PREEMPTS;
-
- if (!initialized)
- {
- mode_spec = Dynarr_new (char);
- mode_string_buffer = Dynarr_new (Emchar);
- internal_cache = Dynarr_new (struct line_start_cache);
- }
-
- /* window system is nil when in -batch mode */
- if (!initialized || noninteractive)
- return;
-
- /* If the user wants to use a window system, we shouldn't bother
- initializing the terminal. This is especially important when the
- terminal is so dumb that emacs gives up before and doesn't bother
- using the window system.
-
- If the DISPLAY environment variable is set, try to use X, and die
- with an error message if that doesn't work. */
-
- #ifdef HAVE_X_WINDOWS
- if (!strcmp (display_use, "x"))
- {
- /* Some stuff checks this way early. */
- Vwindow_system = Qx;
- Vinitial_window_system = Qx;
- Vwindow_system_version = make_number (11);
- return;
- }
- #endif
- #ifdef HAVE_NEXTSTEP
- if (!strcmp (display_use, "ns"))
- {
- Vwindow_system = Qns;
- Vinitial_window_system = Qns;
- Vwindow_system_version = Qzero;
- return;
- }
- #endif
-
- /* If no window system has been specified, try to use the terminal. */
- if (!isatty (0))
- {
- stderr_out ("XEmacs: standard input is not a tty\n");
- exit (1);
- }
-
- /* Look at the TERM variable */
- if (!getenv ("TERM"))
- {
- stderr_out ("Please set the environment variable TERM; see tset(1).\n");
- exit (1);
- }
-
- Vwindow_system_version = Qnil;
- Vinitial_window_system = Qtty;
- }
-
- void
- syms_of_redisplay (void)
- {
- defsymbol (&Qcursor_in_echo_area, "cursor-in-echo-area");
- #if 0
- /* #### Chuck says: I think this needs more thought.
- Think about this for 19.14. */
- defsymbol (&Qpre_redisplay_hook, "pre-redisplay-hook");
- defsymbol (&Qpost_redisplay_hook, "post-redisplay-hook");
- #endif
- defsymbol (&Qdisplay_warning_buffer, "display-warning-buffer");
-
- defsubr (&Sredraw_frame);
- defsubr (&Sredraw_display);
- defsubr (&Sredraw_modeline);
- defsubr (&Sforce_redisplay);
- defsubr (&Sforce_cursor_redisplay);
- defsubr (&Sredisplay_echo_area);
- }
-
- void
- vars_of_redisplay (void)
- {
- #if 0
- staticpro (&last_arrow_position);
- staticpro (&last_arrow_string);
- last_arrow_position = Qnil;
- last_arrow_string = Qnil;
- #endif
-
- updating_line_start_cache = 0;
-
- /* #### Probably temporary */
- DEFVAR_INT ("redisplay-cache-adjustment", &cache_adjustment,
- "(Temporary) Setting this will impact the performance of the internal\n\
- line start cache.");
- cache_adjustment = 2;
-
- DEFVARINT_MAGIC ("pixel-vertical-clip-threshold", &vertical_clip,
- "Minimum pixel height for clipped bottom display line.\n\
- A clipped line shorter than this won't be displayed.",
- redisplay_variable_changed);
- vertical_clip = 5;
-
- DEFVARINT_MAGIC ("pixel-horizontal-clip-threshold", &horizontal_clip,
- "Minimum visible area for clipped glyphs at right boundary.\n\
- Clipped glyphs shorter than this won't be displayed.\n\
- Only pixmap glyph instances are currently allowed to be clipped.",
- redisplay_variable_changed);
- horizontal_clip = 5;
-
- DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
- "String displayed by modeline-format's \"%m\" specification.");
- Vglobal_mode_string = Qnil;
-
- DEFVARLISP_MAGIC ("overlay-arrow-position", &Voverlay_arrow_position,
- "Marker for where to display an arrow on top of the buffer text.\n\
- This must be the beginning of a line in order to work.\n\
- See also `overlay-arrow-string'.", redisplay_variable_changed);
- Voverlay_arrow_position = Qnil;
-
- DEFVARLISP_MAGIC ("overlay-arrow-string", &Voverlay_arrow_string,
- "String to display as an arrow. See also `overlay-arrow-position'.",
- redisplay_variable_changed);
- Voverlay_arrow_string = Qnil;
-
- DEFVAR_INT ("scroll-step", &scroll_step,
- "*The number of lines to try scrolling a window by when point moves out.\n\
- If that fails to bring point back on frame, point is centered instead.\n\
- If this is zero, point is always centered after it moves off frame.");
-
- DEFVARBOOL_MAGIC ("truncate-partial-width-windows",
- &truncate_partial_width_windows,
- "*Non-nil means truncate lines in all windows less than full frame wide.",
- redisplay_variable_changed);
- truncate_partial_width_windows = 1;
-
- DEFVAR_BOOL ("line-number-mode", &line_number_mode,
- "*Whether to display line numbers in the modeline.");
- line_number_mode = 0;
-
- DEFVAR_BOOL ("visible-bell", &visible_bell,
- "*Non-nil means try to flash the frame to represent a bell.");
- visible_bell = 0;
-
- DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
- "*Non-nil means no need to redraw entire frame after suspending.\n\
- A non-nil value is useful if the terminal can automatically preserve\n\
- Emacs's frame display when you reenter Emacs.\n\
- It is up to you to set this variable if your terminal can do that.");
- no_redraw_on_reenter = 0;
-
- /* #### This should be removed in 19.14 */
- DEFVAR_LISP ("window-system", &Vwindow_system,
- "A symbol naming the window-system under which Emacs is running,\n\
- such as `x', or nil if emacs is running on an ordinary terminal.\n\
- This variable is OBSOLETE and will be removed in a future version.");
- Vwindow_system = Qnil;
-
- /* #### Temporary shit until window-system is eliminated. */
- DEFVAR_LISP ("initial-window-system", &Vinitial_window_system,
- "DON'T TOUCH");
- Vinitial_window_system = Qnil;
-
- DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
- "The version number of the window system in use.\n\
- For X windows, this is 10 or 11.");
- Vwindow_system_version = Qnil;
-
- DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
- "Non-nil means put cursor in minibuffer, at end of any message there.");
- cursor_in_echo_area = 0;
-
- /* #### Shouldn't this be generalized as follows:
-
- if nil, use block cursor.
- if a number, use a bar cursor of that width.
- Otherwise, use a 1-pixel bar cursor.
-
- #### Or better yet, this variable should be trashed entirely
- (use a Lisp-magic variable to maintain compatibility)
- and a specifier `cursor-shape' added, which allows a block
- cursor, a bar cursor, a flashing block or bar cursor,
- maybe a caret cursor, etc. */
-
- DEFVAR_LISP ("bar-cursor", &Vbar_cursor,
- "Use vertical bar cursor if non-nil. If t width is 1 pixel, otherwise 2.");
- Vbar_cursor = Qnil;
-
- #if 0
- /* #### Chuck says: I think this needs more thought.
- Think about this for 19.14. */
- DEFVAR_LISP ("pre-redisplay-hook", &Vpre_redisplay_hook,
- "Function or functions to run before every redisplay.\n\
- Functions on this hook must be careful to avoid signalling errors!");
- Vpre_redisplay_hook = Qnil;
-
- DEFVAR_LISP ("post-redisplay-hook", &Vpost_redisplay_hook,
- "Function or functions to run after every redisplay.\n\
- Functions on this hook must be careful to avoid signalling errors!");
- Vpost_redisplay_hook = Qnil;
- #endif
-
- DEFVAR_INT ("display-warning-tick", &display_warning_tick,
- "Bump this to tell the C code to call `display-warning-buffer'\n\
- at next redisplay. You should not normally change this; the function\n\
- `display-warning' automatically does this at appropriate times.");
- display_warning_tick = 0;
-
- DEFVAR_BOOL ("inhibit-warning-display", &inhibit_warning_display,
- "Non-nil means inhibit display of warning messages.\n\
- You should *bind* this, not set it. Any pending warning messages\n\
- will be displayed when the binding no longer applies.");
- /* reset to 0 by startup.el after the splash screen has displayed.
- This way, the warnings don't obliterate the splash screen. */
- inhibit_warning_display = 1;
- }
-
- void
- specifier_vars_of_redisplay (void)
- {
- DEFVAR_SPECIFIER ("left-margin-width", &Vleft_margin_width,
- "*Width of left margin.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vleft_margin_width = Fmake_specifier (Qnatnum);
- set_specifier_fallback
- (Vleft_margin_width,
- list1 (Fcons (Qnil, Qzero)));
- set_specifier_caching (Vleft_margin_width,
- slot_offset (struct window, left_margin_width),
- some_window_value_changed,
- slot_offset (struct frame, left_margin_width),
- margin_width_changed_in_frame);
-
- DEFVAR_SPECIFIER ("right-margin-width", &Vright_margin_width,
- "*Width of right margin.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vright_margin_width = Fmake_specifier (Qnatnum);
- set_specifier_fallback
- (Vright_margin_width,
- list1 (Fcons (Qnil, Qzero)));
- set_specifier_caching (Vright_margin_width,
- slot_offset (struct window, right_margin_width),
- some_window_value_changed,
- slot_offset (struct frame, right_margin_width),
- margin_width_changed_in_frame);
-
- DEFVAR_SPECIFIER ("minimum-line-ascent", &Vminimum_line_ascent,
- "*Minimum ascent height of lines.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vminimum_line_ascent = Fmake_specifier (Qnatnum);
- set_specifier_fallback (Vminimum_line_ascent,
- list1 (Fcons (Qnil, Qzero)));
- set_specifier_caching (Vminimum_line_ascent,
- slot_offset (struct window,
- minimum_line_ascent),
- some_window_value_changed,
- 0, 0);
-
- DEFVAR_SPECIFIER ("minimum-line-descent", &Vminimum_line_descent,
- "*Minimum descent height of lines.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vminimum_line_descent = Fmake_specifier (Qnatnum);
- set_specifier_fallback (Vminimum_line_descent,
- list1 (Fcons (Qnil, Qzero)));
- set_specifier_caching (Vminimum_line_descent,
- slot_offset (struct window,
- minimum_line_descent),
- some_window_value_changed,
- 0, 0);
-
- DEFVAR_SPECIFIER ("use-left-overflow", &Vuse_left_overflow,
- "*Non-nil means use the left outside margin as extra whitespace when\n\
- displaying 'whitespace or 'inside-margin glyphs.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vuse_left_overflow = Fmake_specifier (Qboolean);
- set_specifier_fallback (Vuse_left_overflow,
- list1 (Fcons (Qnil, Qnil)));
- set_specifier_caching (Vuse_left_overflow,
- slot_offset (struct window,
- use_left_overflow),
- some_window_value_changed,
- 0, 0);
-
- DEFVAR_SPECIFIER ("use-right-overflow", &Vuse_right_overflow,
- "*Non-nil means use the right outside margin as extra whitespace when\n\
- displaying 'whitespace or 'inside-margin glyphs.\n\
- This is a specifier; use `set-specifier' to change it.");
- Vuse_right_overflow = Fmake_specifier (Qboolean);
- set_specifier_fallback (Vuse_right_overflow,
- list1 (Fcons (Qnil, Qnil)));
- set_specifier_caching (Vuse_right_overflow,
- slot_offset (struct window,
- use_right_overflow),
- some_window_value_changed,
- 0, 0);
- }
-